home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 October: Mac OS SDK / Dev.CD Oct 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw GX / Programming Stuff / Sample Code / Printing Samples / Printer Drivers… / ImageWriter--DTP renamer / NewApp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-15  |  80.5 KB  |  2,861 lines  |  [TEXT/MPS ]

  1. /*
  2.     copyright © 1991-1996 Apple Computer Inc.  All rights reserved.
  3.     
  4.     NewApp.c
  5.     This file contains all new API implementations for the ImageWriter driver.
  6.     
  7.     Modification history
  8.     03/19/91        TED                New file today
  9.     04/23/91        Sam Weiss        Changed Inherit to Forward
  10.     05/29/91        TED                Added manual feed and faster mode support
  11.     12/20/93        dmh                Sync'd with the shipping 1.0b3 GX driver.
  12.     03/24/94        Ken Hittleman    Updated manual feed to use gxTrayFeedInfo
  13.     03/30/94        Ken Hittleman    Added call to paper matching CheckStatus when switching to auto-feed
  14.      6/23/94        dmh                Added desktop printer renaming code.
  15.     07/05/94        Ken Hittleman    Removed set color and page size from IW I path, which blew cookies on it
  16.     08/26/94        dmh                Sync'd with the shipping 1.0.1 GX driver.
  17.      6/14/96        cn                Updated to support Universal Interfaces 2.1.
  18. */
  19.  
  20. #include <memory.h>
  21. #include <Devices.h>
  22. #include <Folders.h>
  23. #include <Errors.h>
  24. #include <ToolUtils.h>
  25. #include <Resources.h>
  26. #include <Packages.h>
  27. #include <GXPrinterDrivers.h>
  28. #include <GXPrinting.h>
  29. #include <FixMath.h>
  30. #include <GXMath.h>
  31. #include <Graphics Routines.h>
  32. #include <GraphicsLibraries.h>
  33. #include <FontLibrary.h>
  34. #include <GXLayout.h>
  35. #include <GXExceptions.h>
  36. #include <PrintingLibraries.h>
  37.  
  38. #include "CommonDefines.h"
  39.  
  40. OSErr MyRenameDTPs(void);
  41.  
  42. /* ------------------------------------------------------------------------------------    */
  43. /*    INTERNAL DEFINES                                                                    */
  44. /* ------------------------------------------------------------------------------------    */    
  45.  
  46. // positive error for aborting job and placing on hold
  47. #define kPutJobOnHoldErr            3
  48.  
  49. // timeout (in ticks) for the initial query
  50. #define kQueryTimeout                (7*60);
  51.  
  52. // things this specific driver puts into the DTP config file
  53. #define    kImageWriterConfigType        'ifig'
  54. #define kImageWriterConfigID        (0)            
  55. typedef struct
  56.     {
  57.         Boolean    hasColorRibbon;
  58.         Boolean    hasSheetFeeder;
  59.         Boolean    isImageWriterII;        // is this an ImageWriter II, or an older model?
  60.     } ImageWriterConfigRecord, *ImageWriterConfigPtr, ** ImageWriterConfigHandle;
  61.     
  62. /* Define special characters needed */
  63. #define ESCAPE                (char) 27
  64.  
  65. /* A record to hold a set margins command */
  66. typedef struct SetMarginsRecord
  67.     {
  68.     char        cEscape;                    // ESCAPE character
  69.     char        cCommand;                    // Set Margins command character
  70.     char        cIndentDistance[4];            // number of dots to indent
  71.     } SetMarginsRecord, *SetMarginsPtr;
  72. #define kSetMarginsCommand    (char)'F'        // ImageWriter II uses 'F' for tabbing
  73. #define kSetMarginsSize        6
  74.  
  75. /*     Define a record that can hold one scan line's worth of data, 1280 will
  76.     only happen at 160 dpi. and 14 inch wide paper.   */
  77. typedef struct ScanLineRecord
  78.     {
  79.     char            cColorEscape;                    // ESCAPE character
  80.     char            cSetColorCommand;                // Set color command
  81.     char            cColor;                            // The color
  82.     char            cEscape;                        // ESCAPE character
  83.     char            cCommand;                        // 'enter graphics' command
  84.     char            cLineLength[4];                    // number of dots to print
  85.     char            iTheData[2240];                    // Bits for the data, enough for one line's worth
  86.     } ScanLineRecord, *ScanLinePtr;
  87. #define kGraphicsCommand    (char)'G'        /* graphics printing command */
  88. #define kRepeatGroup        (char)'V'        /* repeat group character */
  89. #define kSetColorCommand     (char)'K'        /* Set color command */
  90. #define kGroupSize            6                /* Size of one group header */
  91.  
  92. #define kScanLineSize         3                /* NOTE: this is just the header size! */
  93.  
  94. #define kStatusCommand        "\033?"            /* request device status/config */
  95.  
  96. // Status flags for PAP status queries
  97. #define    kColorRibbonBit        0
  98. #define kSheetFeederBit        1
  99. #define kPaperOutBit        2
  100. #define kCoverOpenBit        3
  101. #define kOffLineBit            4
  102. #define kPaperJamBit        5
  103. #define kPrinterFaultBit    6
  104. #define kHeadMovingBit        7
  105. #define kPrinterBusyBit        8
  106.  
  107. #define kOutOfPaperMask            (  (0x8000 >> kPaperJamBit) | (0x8000 >> kCoverOpenBit) | (0x8000 >> kOffLineBit) )
  108. #define kPrinterOfflineMask        (  (0x8000 >> kOffLineBit) )
  109. #define kPrinterBusyMask        (  (0x8000 >> kPrinterBusyBit) )
  110. #define kHeadMovingMask            (  (0x8000 >> kHeadMovingBit) )
  111.  
  112. //<FF>
  113. /* ------------------------------------------------------------------------------------    */
  114. /*    INTERNAL ROUTINES                                                                */
  115. /* ------------------------------------------------------------------------------------    */
  116. void Long2Dec(long aLong, Ptr emitHere)
  117. /*
  118.     Converts a long into an ASCII string, padded with leading zeros.
  119. */
  120. {    
  121.     char    aString[10];
  122.     short    i, actualWidth, strLength;
  123.     
  124.     NumToString(aLong, (unsigned char *) aString);
  125.     
  126.     // Get the width of the string, check for being too small
  127.     strLength = aString[0];
  128.     actualWidth = strLength;
  129.     if (actualWidth < 4)
  130.         actualWidth = 4;
  131.         
  132.     // output the string, padding with the requested character
  133.     strLength = actualWidth-strLength;
  134.     for (i = 0; i < actualWidth; ++i)
  135.         {
  136.         *emitHere++ = (i < strLength) 
  137.             ? '0' : aString[(i+1)-(strLength)];
  138.         }
  139.         
  140. } // Long2Dec
  141.  
  142.  
  143. //<FF>
  144. /* ------------------------------------------------------------------------------------    */
  145. Boolean PrinterHasColorRibbon(gxPrinter thePrinter)
  146. /*
  147.     Returns true if the config file says that the printer is blessed with a color ribbon,
  148.     false if it is a black and white ribbon.
  149. */
  150. {
  151.     Boolean                        hasColor = true;
  152.     Str32                        deviceName;
  153.     OSErr                        anErr;
  154.     ImageWriterConfigHandle        configHandle;
  155.     
  156.     // if not formatting to a particular device, assume color ribbon, for widest range of colorSpaces
  157.     GXGetPrinterName(thePrinter, deviceName);
  158.     if (deviceName[0] != 0)
  159.         {
  160.         // if we are going to a particular device, assume no color, as that is more common
  161.         hasColor = false;
  162.         
  163.         anErr = GXFetchDTPData(deviceName, kImageWriterConfigType, kImageWriterConfigID, &(Handle)configHandle);
  164.         if (anErr == noErr)
  165.             {
  166.             hasColor = (**configHandle).hasColorRibbon;
  167.             DisposHandle((Handle) configHandle);
  168.             }
  169.         }
  170.     
  171.     return(hasColor);
  172.     
  173. } // PrinterHasColorRibbon
  174.  
  175.  
  176. //<FF>
  177. /* ------------------------------------------------------------------------------------    */
  178. gxViewDevice    NewDeviceResolutionViewDevice(void)
  179. /*
  180.     This routine creates a viewDevice and gives it a scale factor in it's mapping
  181.     appropriate for this device (144 dpi in the case of the IW)
  182. */
  183. {
  184.     gxViewDevice        vd;
  185.     
  186.     // create the viewDevices with a fake bitmap
  187.     {
  188.     gxShape        tempBitmap;
  189.     gxBitmap        aBitmap;
  190.     
  191.     aBitmap.pixelSize     = 1;
  192.     aBitmap.rowBytes     = 0;
  193.     aBitmap.width         = 0;
  194.     aBitmap.height         = 0;
  195.     aBitmap.image         = (char*)gxMissingImagePointer;
  196.     aBitmap.space         = gxNoSpace;
  197.     aBitmap.set         = nil;
  198.     aBitmap.profile     = nil;
  199.     
  200.     tempBitmap = GXNewBitmap(&aBitmap, nil);
  201.     vd = GXNewViewDevice(gxScreenViewDevices, tempBitmap);
  202.     GXDisposeShape(tempBitmap);
  203.     }
  204.  
  205.     // setup a mapping for a 144 (2X) viewDevice
  206.     {
  207.     gxMapping    vdMapping;
  208.     
  209.     ResetMapping(&vdMapping);
  210.     ScaleMapping(&vdMapping, ff(2), ff(2), ff(0), ff(0));
  211.     
  212.     GXSetViewDeviceMapping(vd, &vdMapping);
  213.     }
  214.     
  215.     return(vd);
  216.     
  217. } // NewDeviceResolutionViewDevice
  218.  
  219. //<FF>
  220. /* ------------------------------------------------------------------------------------    */
  221. Boolean    JobIsBest(long *imagewriterOptions)
  222. /*
  223.     Returns true if the current job is a final quality mode job, else returns false.
  224.     Also, returns the imagewriter rendering options.
  225. */
  226. {
  227.     Boolean            isFinal;
  228.     gxQualityInfo    jobQualitySettings;
  229.     long            itemSize = sizeof(jobQualitySettings);
  230.     OSErr            status;
  231.     Collection        jobCollection;
  232.     
  233.     // cache the collection
  234.     jobCollection = GXGetJobCollection(GXGetJob());
  235.     
  236.     // find out the info
  237.         
  238.     isFinal = false;
  239.     
  240.     status = GetCollectionItem(jobCollection, 
  241.                                     gxQualityTag, gxPrintingTagID, 
  242.                                     &itemSize, &jobQualitySettings);
  243.     
  244.     if ( (status == noErr) && (jobQualitySettings.currentQuality == (jobQualitySettings.qualityCount-1)) )
  245.         isFinal = true;
  246.     
  247.     ncheck( status );
  248.  
  249.     // we default to super res
  250.     *imagewriterOptions = kSuperRes;
  251.     itemSize = sizeof(imagewriterOptions);
  252.     status = GetCollectionItem(jobCollection, 
  253.                                     DriverCreator, 0, 
  254.                                     &itemSize, imagewriterOptions);
  255.                 
  256.     // and return the job quality mode
  257.     return(isFinal);
  258.     
  259. } // JobIsBest
  260.  
  261.  
  262. //<FF>
  263. /* ------------------------------------------------------------------------------------    */
  264.  
  265. OSErr    DoTheQuery(unsigned short * statusReturn, Boolean papStatus)
  266. /*
  267.     Returns in statusString the current status for the printer.  Returns various
  268.     errors from IO package if the printer's status could not be found.
  269. */
  270. {
  271.     OSErr                anErr = noErr;
  272.     long                statusLength;                    // status string size
  273.     SpecGlobalsHdl         hGlobals = GetMessageHandlerInstanceContext();
  274.  
  275.     // default to a clear status
  276.     *statusReturn = 0;
  277.  
  278.     // send the query
  279.     if (papStatus)
  280.         {
  281.         char    statusString[255];                // returned string
  282.         
  283.         // According to the old IW driver, sometimes it will return all of the bits
  284.         // set.  This is an error, but we can just try again.
  285.         do {
  286.             statusLength = 255;
  287.             anErr = Send_GXGetDeviceStatus(nil, 0, statusString, &statusLength, nil);
  288.             } while ( (anErr == noErr) && (statusString[0] == 0xFF) );
  289.         
  290.         // return the printer status bits in the PAP case
  291.         *statusReturn = *(unsigned short*)&statusString[0];
  292.         }
  293.     else
  294.         {
  295.         char    statusString[8];                // returned string
  296.  
  297.         if ((**hGlobals).isImageWriterII)
  298.             {
  299.             statusLength = 8; // max number of characters to get back
  300.             anErr = Send_GXGetDeviceStatus(kStatusCommand, 2, statusString, &statusLength, "\p\n");
  301.                 
  302.             if ( anErr == gxAioTimeout)
  303.                 {
  304.                 *statusReturn = kPrinterOfflineMask;
  305.                 anErr = noErr;
  306.                 }
  307.             else
  308.                 {
  309.                 if (anErr == noErr)
  310.                     {
  311.                     // generate printer status bits in the serial case
  312.                     if (statusString[4] == 'C')
  313.                         *statusReturn |= 0x8000 >> kColorRibbonBit;
  314.                     if ( (statusString[5] == 'F') || (statusString[4] == 'F') )
  315.                         *statusReturn |= 0x8000 >> kSheetFeederBit;
  316.                     }
  317.                 }
  318.             }
  319.         }
  320.         
  321.     nrequire(anErr, Send_GXGetDeviceStatus);
  322.  
  323. // FALL THROUGH EXCEPTION HANDLING    
  324. Send_GXGetDeviceStatus:
  325.     
  326.     return(anErr);
  327.  
  328. } // DoTheQuery
  329.  
  330. //<FF>
  331. /* ------------------------------------------------------------------------------------    */
  332. OSErr FetchStatusString(unsigned short * statusReturn, Boolean papStatus, Boolean doRetry)
  333. /*
  334.     Returns in statusString the current status for the printer.  Returns various
  335.     errors from IO package if the printer's status could not be found.
  336.     
  337.     Handles reporting error conditions to the user.
  338. */
  339. {
  340.     OSErr            anErr;
  341.     SpecGlobalsHdl         hGlobals = GetMessageHandlerInstanceContext();
  342.     
  343.     anErr = DoTheQuery(statusReturn, papStatus);        
  344.     nrequire(anErr, Send_GXGetDeviceStatus);
  345.     
  346.     // printer offline?
  347.     if (     
  348.         (doRetry) &&
  349.         ( ((*statusReturn) & kPrinterOfflineMask) != 0 )  
  350.         )
  351.         {
  352.         gxStatusRecord        theStat;
  353.         gxStatusRecord        *pStat = &theStat;
  354.         Boolean                printerIsFixed = false;
  355.         
  356.         pStat->statusOwner    = 'drvr';
  357.         pStat->statResId     = kDriverStatus;        
  358.         pStat->statResIndex = kCheckOnline;            
  359.         pStat->bufferLen      = 0;
  360.         pStat->dialogResult = 0;
  361.         
  362.  
  363.         // keep sending the user the alert until either
  364.         //  a) the problem resolves itself
  365.         //  b) the user responds via the dialog
  366.         //  c) some other (fatal) error happens
  367.         do
  368.             {
  369.             
  370.             // tell the user
  371.             anErr = GXAlertTheUser(pStat);
  372.             
  373.             // based on the user's response, continue or cancel
  374.             switch (pStat->dialogResult)
  375.                 {
  376.                 case ok:
  377.                     // retry
  378.                     break;
  379.                     
  380.                 case cancel:
  381.                     anErr = gxPrUserAbortErr;
  382.                     break;
  383.                     
  384.                 case 3:
  385.                     anErr = kPutJobOnHoldErr;
  386.                     break;
  387.                 }
  388.                 
  389.             // error to return from next idle
  390.             (**hGlobals).idleError = anErr;
  391.  
  392.             // if printer got suddenly turned online, do an OK
  393.             if ( (anErr == noErr) && ((papStatus) || (pStat->dialogResult == ok)) )
  394.                 {
  395.                 pStat->dialogResult = 0;
  396.                 (void) DoTheQuery(statusReturn, papStatus);        
  397.                 if (     
  398.                     ( ((*statusReturn) & kPrinterOfflineMask) == 0 ) 
  399.                     )
  400.                     {
  401.                     printerIsFixed = true;
  402.                     pStat->dialogResult = ok;
  403.                     anErr = noErr;
  404.                     }
  405.                 }
  406.                 
  407.             } while ((anErr == noErr) && (pStat->dialogResult == 0));
  408.  
  409.         // printer is okay -- no error
  410.         if (printerIsFixed)
  411.             anErr = noErr;
  412.         
  413.         // display "sending data to the printer" message
  414.         if (anErr == noErr)
  415.             anErr = GXReportStatus(kDriverStatus, kSendingData);
  416.         }
  417.  
  418. // FALL THROUGH EXCEPTION HANDLING    
  419. Send_GXGetDeviceStatus:
  420.     
  421.     return(anErr);
  422.     
  423. } // FetchStatusString
  424.  
  425. //<FF>
  426. /* ------------------------------------------------------------------------------------    */
  427. OSErr UpdateConfiguration(void)
  428. /*
  429.     This routine queries the printer for its hardware configuration (color ribbon and
  430.     sheet feeder options), and stores that info into the configuration file.
  431. */
  432. {
  433.     SpecGlobalsHdl                 hGlobals = GetMessageHandlerInstanceContext();
  434.     Str32                        deviceName;
  435.     OSErr                        anErr = noErr;
  436.     ImageWriterConfigHandle        configHandle;
  437.     ImageWriterConfigPtr        configPtr;
  438.     Boolean                        isImageWriterII = false;
  439.     ResType                        commType;
  440.     
  441.         
  442.     // find out what we are printing to, and how we are connected
  443.     GXGetPrinterName(GXGetJobOutputPrinter(GXGetJob()), deviceName);
  444.     anErr = GXFetchDTPData(deviceName, gxDeviceCommunicationsType, gxDeviceCommunicationsID, (Handle*)&configHandle);
  445.     nrequire(anErr, FetchCommType);
  446.     commType = **(ResType**)configHandle;
  447.     DisposHandle((Handle) configHandle);
  448.     
  449.     
  450.     // store away the communications type for future use
  451.     {
  452.     SpecGlobalsHdl             hGlobals = GetMessageHandlerInstanceContext();
  453.     
  454.     (**hGlobals).commType = commType;
  455.     }
  456.     
  457.     // find out the original configuration
  458.     if (GXFetchDTPData(deviceName, kImageWriterConfigType, kImageWriterConfigID, (Handle*)&configHandle) == noErr)
  459.         {
  460.         // remember if we thought we had an IW2 when we started
  461.         configPtr = *configHandle;
  462.         (**hGlobals).isImageWriterII = isImageWriterII = configPtr->isImageWriterII;
  463.         DisposeHandle((Handle) configHandle);
  464.  
  465.         // if we aren't an ImageWriter II, bail out now - because the timeout takes two minutes!
  466.         if (!isImageWriterII)
  467.             return(noErr);            
  468.         }
  469.     else
  470.         {        
  471.         // if we don't know yet, assume IW2 for PAP else Serial
  472.         if (commType == 'PPTL')
  473.             isImageWriterII = true;
  474.             
  475.         // Assume IW 2 so we do the query for real
  476.         (**hGlobals).isImageWriterII = true;
  477.         }
  478.         
  479.     // make a handle to hold our configuration information for the printer
  480.     configHandle = (ImageWriterConfigHandle) NewHandle(sizeof(ImageWriterConfigRecord) );
  481.     anErr = MemError();
  482.     nrequire(anErr, NewHandle);
  483.     
  484.     // setup the default for the device - in case the query fails
  485.     configPtr = *configHandle;
  486.     configPtr->hasColorRibbon = false;
  487.     configPtr->hasSheetFeeder = false;
  488.     configPtr->isImageWriterII = true;
  489.     
  490.     // send initial data first to make sure IO handshaking is working,
  491.     // to load the first sheet of paper into the feeder (if any),
  492.     // and to take up "gear lash" in the device.  This is copied from
  493.     // what the old driver did.  Not doing this will cause the sheet
  494.     // feeder not to feed the initial page of data.
  495.     {
  496.     char    sendBuffer[11];
  497.     
  498.     // <CR>
  499.     sendBuffer[0] = 0x0D;
  500.     
  501.     // linefeed size = 18/144th
  502.     sendBuffer[1] = ESCAPE;
  503.     sendBuffer[2] = 'T';
  504.     sendBuffer[3] = '1';
  505.     sendBuffer[4] = '8';
  506.     
  507.     // reverse line feed
  508.     sendBuffer[5] = ESCAPE;
  509.     sendBuffer[6] = 'r';
  510.     sendBuffer[7] = 0x0A;
  511.     
  512.     // forward line feed
  513.     sendBuffer[8] = ESCAPE;
  514.     sendBuffer[9] = 'f';
  515.     sendBuffer[10] = 0x0A;
  516.     
  517.     anErr = Send_GXWriteData(sendBuffer, 11);
  518.     nrequire(anErr, Failed_SendInitialData);
  519.     }
  520.     
  521.     {
  522.     unsigned short    statusReturn;
  523.     
  524.     // query the device
  525.     if ((isImageWriterII) && (commType == 'SPTL') )
  526.         (**hGlobals).idleTimeout = TickCount() + kQueryTimeout;
  527.     anErr = FetchStatusString(&statusReturn, (commType == 'PPTL'), isImageWriterII);
  528.     if ( (anErr == noErr) && ( (statusReturn & kPrinterOfflineMask) != 0 )  )
  529.         anErr = gxAioTimeout;
  530.     (**hGlobals).idleTimeout = 0;
  531.     (void) GXReportStatus(kDriverStatus, kSendingData);
  532.     
  533.     // and scan the string looking for information about printer kind and options
  534.     configPtr = *configHandle;
  535.     if ( anErr == gxAioTimeout )
  536.         {
  537.         // if we timeout and we don't know the printer kind - assume IW1
  538.         if (!isImageWriterII)
  539.             {
  540.             anErr = noErr;
  541.             isImageWriterII = configPtr->isImageWriterII = false;
  542.             }
  543.         }
  544.     else
  545.         {
  546.         isImageWriterII = true;
  547.         configPtr->hasColorRibbon = (statusReturn & (0x8000 >> kColorRibbonBit)) != 0;
  548.         configPtr->hasSheetFeeder = (statusReturn & (0x8000 >> kSheetFeederBit)) != 0;
  549.         }
  550.     nrequire(anErr, FetchStatusString);
  551.     }
  552.     
  553.     // Remember if this was an ImageWriter II after the query
  554.     (**hGlobals).isImageWriterII = isImageWriterII;
  555.     
  556.     // write out the new configuration
  557.     anErr = GXWriteDTPData(deviceName, kImageWriterConfigType, kImageWriterConfigID, (Handle)configHandle);
  558.     
  559.     
  560. // CLEANUP EXCEPTION HANDLING
  561. FetchStatusString:
  562. Failed_SendInitialData:
  563.     DisposHandle((Handle) configHandle);
  564.     
  565. NewHandle:
  566. Send_GXWriteData:
  567. FetchCommType:
  568.     return(anErr);
  569.     
  570. } // UpdateConfiguration
  571.  
  572.  
  573. /* ------------------------------------------------------------------------------------    */
  574. OSErr WriteDraftChars(long **draftTable, unsigned char *draftChar, long numChars)
  575. /*
  576.     This routine writes out a single character in the native set of the printer.
  577.     It uses a table that's part of the driver to do the right thing in order to generate this
  578.     character.
  579. */
  580. {
  581.     OSErr        anErr = noErr;
  582.     char        outputChars[20];                // a maximum of 20 characters can be generated
  583.     short        charCount;                    
  584.     
  585.     // For each character in the buffer, determine how to map the character to a draft character
  586.     for (; numChars > 0; --numChars, ++draftChar)
  587.     {
  588.         // No characters yet for this output character
  589.         charCount = 0;
  590.             
  591.         // Only consider characters in the printable range
  592.         if (*draftChar >= 0x20)
  593.         {
  594.             unsigned long    draftControl = (*draftTable)[*draftChar-0x20];    // Fetch native mode long word corresponding to this character
  595.             unsigned char    outChar;
  596.             unsigned char    nationalSet;
  597.             short                i;
  598.             
  599.             // For each word which composes the native mode long word 
  600.             for (i = 1; i >= 0; --i)
  601.             {
  602.                 // Should we send a backspace character (to overstrike)?
  603.                 if ( (draftControl & 0x80000000) != 0 )
  604.                     outputChars[charCount++] = 0x08;
  605.                 
  606.                 outChar = (draftControl >> 16) & 0xFF;
  607.                 if (outChar != 0)
  608.                 {
  609.                     // Determine the national character set to select
  610.                     nationalSet = (draftControl >> 24) & 0xF;    
  611.     
  612.                     //    Is this character in the standard, built-in character set?
  613.                     if (nationalSet == 0)
  614.                     {
  615.                         outputChars[charCount++] = outChar;
  616.                     }
  617.                     else    //    T => Must select a foreign language character set 
  618.                     {
  619.                         outputChars[charCount++] = 0x1B;
  620.                         outputChars[charCount++] = 0x44;
  621.                         outputChars[charCount++] = nationalSet;
  622.                         outputChars[charCount++] = 0x00;
  623.                         outputChars[charCount++] = outChar;
  624.                         outputChars[charCount++] = 0x1B;                // We always switch back to the kAmerican character set
  625.                         outputChars[charCount++] = 0x5A;
  626.                         outputChars[charCount++] = 0x07;
  627.                         outputChars[charCount++] = 0x00;
  628.                     }
  629.                 }
  630.                 
  631.                 // Take the next (low) word and process it (if we're not all done)
  632.                 draftControl <<= 16;
  633.             }    
  634.         }
  635.             
  636.         // If we generated any data, send it out now
  637.         if (charCount > 0)
  638.             anErr = Send_GXBufferData(outputChars, charCount, gxNoBufferOptions);
  639.     }
  640.         
  641.     return(anErr);    
  642.     
  643. } // WriteDraftChars
  644.  
  645. /* ------------------------------------------------------------------------------------    */
  646. OSErr GetPointerThisBig(Ptr *theBuff, long numBytes) 
  647. {
  648.     OSErr        anErr = noErr;
  649.     
  650.     if (*theBuff != nil)
  651.     {
  652.         if ( GetPtrSize(*theBuff) < numBytes )    //    T => Won't be big enough; make a new one
  653.         {
  654.             DisposPtr(*theBuff);
  655.             *theBuff = nil;
  656.         }
  657.     }
  658.  
  659.     if (*theBuff == nil)
  660.     {
  661.         *theBuff = NewPtrClear(numBytes);
  662.         anErr = MemError();
  663.     }
  664.     
  665.     return(anErr);
  666.     
  667. } // GetPointerThisBig
  668.  
  669. /* ------------------------------------------------------------------------------------    */
  670. OSErr GetTextAndPosition(    gxShape            theShape, 
  671.                             Ptr                *theChars, 
  672.                             long            *numChars, 
  673.                             gxPoint            *textPosition)
  674. {
  675.     OSErr        anErr = noErr;
  676.     long        textLength;
  677.     
  678.     // Determine the size of the text data and the position of the text
  679.     textLength = GXGetLayout(theShape, nil, nil, nil, nil, nil, nil, nil, nil, textPosition);
  680.  
  681.     // Make sure we have a buffer pointer large enough to hold all of the data
  682.     
  683.     anErr = GetPointerThisBig(theChars, textLength);
  684.     require(anErr == noErr, CantAllocTextBuff);
  685.     
  686.     // Now we retrieve the text
  687.     GXGetLayout(theShape, *theChars, nil, nil, nil, nil, nil, nil, nil, nil);
  688.     
  689.     // Remember the number of characters in the shape
  690.     *numChars = textLength;
  691.     
  692.  
  693. /******* Clean-up *******/
  694.  
  695. CantAllocTextBuff:
  696.     return(anErr);
  697.     
  698. } // GetTextAndPosition
  699.  
  700. /* ------------------------------------------------------------------------------------    */
  701. OSErr PrintPageInDraftMode(gxShape thePage, gxRasterImageDataHdl imageData)
  702. {
  703.     OSErr                    anErr = noErr;
  704.     long                    i;
  705.     long                    numItems;
  706.     Fixed                    currYPos = ff(0);
  707.     Ptr                        theChars = nil;
  708.     long                    numChars = 0;
  709.     gxPoint                    textPosition;
  710.     Fixed                    oldTextSize = ff(0);
  711.     SpecGlobalsHdl             hGlobals = GetMessageHandlerInstanceContext();
  712.     
  713.     // Since the page picture we need to process is a picture shape that's embedded in
  714.     // thePage (a shape containing one item => a picture), we need to extract the real
  715.     // page picture from thePage.
  716.     
  717.     thePage = GetPictureItem(thePage, 1, nil, nil, nil, nil);
  718.     numItems = GXGetPicture(thePage, nil, nil, nil, nil);
  719.     
  720.     // For each shape within the picture, check its type and process it accordingly
  721.     
  722.     for (i = 1; i <= numItems; ++i)
  723.     {
  724.         gxShape                theShape;
  725.         short                theType;
  726.                 
  727.         theShape = GetPictureItem(thePage, i, nil, nil, nil, nil);
  728.         theType = GXGetShapeType(theShape);
  729.         
  730.         if (theType == gxLayoutType)    //    T => We have a layout shape
  731.         {
  732.             Fixed        textSize;
  733.             char        buff[12];
  734.             char        theFace;
  735.             short        cmndBuffSz;
  736.             
  737.             // First determine the style in which we're printing
  738.             
  739.             theFace = GetStyleCommonFace( GXGetShapeStyle(theShape) );
  740.             
  741.             buff[0] = ESCAPE;
  742.             if ( (theFace & bold) != 0 )    //    T => Turn bold facing on
  743.                 buff[1] = '!';
  744.             else                                    //    T => Turn it off
  745.                 buff[1] = '"';
  746.             
  747.             buff[2] = ESCAPE;
  748.             if ( (theFace & underline) != 0 )    //    T => Turn underline facing on
  749.                 buff[3] = 'X';
  750.             else                                            //    T => Turn it off
  751.                 buff[3] = 'Y';
  752.                 
  753.             cmndBuffSz = 4;
  754.             
  755.             // Next determine if we need to change the size of the font being used
  756.             
  757.             textSize = GXGetShapeTextSize(theShape);
  758.             if (textSize != oldTextSize)    //    T => Must issue LQ command to change font size
  759.             {
  760.                 buff[4] = ESCAPE;                //    The first escape command selects black color
  761.                 buff[5] = kSetColorCommand;
  762.                 buff[6] = '0';
  763.                 
  764.                 buff[7] = ESCAPE;                //    The second escape command selects a draft font
  765.                 buff[8] = 'a';
  766.                 buff[9] = '1';
  767.                 
  768.                 buff[10] = ESCAPE;                //    The third escape command selects the character pitch
  769.                 
  770.                 if ( textSize <= ff(10) )    //    T => Select 10 cpi
  771.                 {
  772.                     buff[11] = 'N';
  773.                 }
  774.                 else    //    T => All other sizes get mapped to 12 cpi
  775.                 {
  776.                     buff[11] = 'E';
  777.                 }
  778.                 
  779.                 // Remember the last text size
  780.                 oldTextSize = textSize;    
  781.                 
  782.                 // Adjust the size of the data to be sent to the printer
  783.                 cmndBuffSz += 8;
  784.             }
  785.             // else - no change in font size
  786.             
  787.             // Send the commands to the printer
  788.             anErr = Send_GXBufferData(buff, cmndBuffSz, gxDontSplitBuffer);
  789.             require(anErr == noErr, CantSendFontCmnd);
  790.  
  791.             // Get the ASCII text and the starting position of the data
  792.             anErr = GetTextAndPosition(theShape, &theChars, &numChars, &textPosition);
  793.             require(anErr == noErr, CantGetTextAndPos);
  794.             
  795.             if ( (currYPos != ff(0)) && (currYPos != textPosition.y) )    //    T => Moving to a lower line, finish the last ;line with a CR
  796.             {
  797.                 char        c = 0x0D;
  798.                 
  799.                 anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
  800.                 require(anErr == noErr, CantSendCRCmnd);
  801.             }
  802.             
  803.             // Position the print head to the proper location on the page
  804.             {
  805.                 gxMapping                theMapping;
  806.                 long                    lineFeedSize;
  807.                 Str255                    positionCmndsBuff;
  808.                 unsigned long            bytesInBuff = 0;
  809.                 char                    *p;
  810.  
  811.                 GXGetShapeMapping(theShape, &theMapping);
  812.                 MapPoints(&theMapping, (long) 1, &textPosition);    //    Just map the first point
  813.                 
  814.                 // Now position the print head vertically
  815.  
  816.                 lineFeedSize = (textPosition.y - currYPos) >> 16;
  817.                 anErr = Send_GXRasterLineFeed (&lineFeedSize, (char *) positionCmndsBuff, &bytesInBuff, imageData);
  818.                 require(anErr == noErr, CantEmitLineFeeds);
  819.                 
  820.                 // Update the current Y position pointer on the page
  821.                 currYPos = textPosition.y;
  822.  
  823.                 // Now position the print head horizontally on the page
  824.  
  825.                 p = (char *) &positionCmndsBuff[bytesInBuff];        
  826.                 *p++ = ESCAPE;
  827.                 *p++ = 'F';
  828.                 Long2Dec((*hGlobals)->leftMargin + FixedToInt(textPosition.x), p);    // Convert left margin into ASCII and place it at the start of the scan line
  829.                 
  830.                 // Update the number of bytes in the buffer
  831.                 bytesInBuff += 6;
  832.  
  833.                 // Send the positioning info to the printer
  834.                 anErr = Send_GXBufferData
  835.                     ((char *) positionCmndsBuff,
  836.                      bytesInBuff,
  837.                     gxDontSplitBuffer);
  838.                 require(anErr == noErr, CantSendPositionCmnds);
  839.             }
  840.             
  841.             // Now we send the text data to the printer
  842.             anErr = WriteDraftChars((long **) (*hGlobals)->draftTable, (unsigned char *) theChars, numChars);
  843.             require(anErr == noErr, CantWriteChars);
  844.         }
  845.     }    // for
  846.  
  847.     // Send one last CR to wrap the last line (if there was one)
  848.     {
  849.         char        c = 0x0D;
  850.         
  851.         anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
  852.     }
  853.  
  854.  
  855. /******* Clean-up *******/
  856.  
  857. CantWriteChars:
  858. CantSendPositionCmnds:
  859. CantEmitLineFeeds:
  860. CantSendCRCmnd:
  861. CantGetTextAndPos:
  862. CantSendFontCmnd:
  863.     if (theChars != nil)
  864.         DisposPtr(theChars);
  865.                 
  866.     return(anErr);
  867.     
  868. } // PrintPageInDraftMode 
  869.  
  870. //<FF>
  871. /* ------------------------------------------------------------------------------------    */
  872. /*    SPECIFIC DRIVER UNIVERSAL OVERRIDES                                                    */
  873. /* ------------------------------------------------------------------------------------    */
  874. OSErr SD_Initialize (void) 
  875. /*
  876.     The SD_Initalize message is called when a new job is created.  The standard
  877.     thing to do is to allocate and fill out your globals as you see fit.
  878. */
  879. {
  880.  
  881.     SpecGlobalsHdl     hGlobals;
  882.     OSErr             anErr;
  883.         
  884.     // we make our globals
  885.     hGlobals = (SpecGlobalsHdl) NewHandleClear( sizeof(SpecGlobals) );
  886.     anErr = MemError();
  887.  
  888.     // and we save them away
  889.     SetMessageHandlerInstanceContext(hGlobals);
  890.  
  891.     // is everything okay?
  892.     nrequire(anErr, MNewHandleClear);
  893.     
  894.     // Don't need to initialize because of the NewHandleCLEAR
  895.     //(**hGlobals).draftTable = nil;
  896.     //(**hGlobals).lineFeeds = 0;
  897.     //(**hGlobals).packagingOptions = kNoPackagingOptions;
  898.     //(**hGlobals).idleError         = noErr;
  899.     //(**hGlobals).idleQuery         = false;
  900.     //(**hGlobals).idleTimeout         = 0;
  901.     //(**hGlobals).timeoutPending     = false;
  902.     
  903.     
  904.     return(noErr);
  905.     
  906.     
  907. /*-----EXCEPTION HANDLING------*/
  908.  
  909.  
  910. MNewHandleClear:
  911.     return(anErr);
  912.     
  913. } // SD_Initialize
  914.  
  915.  
  916. //<FF>
  917. /* ------------------------------------------------------------------------------------    */
  918. OSErr SD_ShutDown(void) 
  919. /*
  920.     Shutdown is called when the job is done with.  A good thing to do is to get
  921.     rid of any additional storage that is laying around.
  922. */
  923. {
  924.     // clean up our stuff
  925.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  926.  
  927.     // get rid of the draft table (if we have one)
  928.     if (hGlobals)
  929.         DisposHandle((**hGlobals).draftTable);
  930.     
  931.     // we get rid of our storage
  932.     DisposHandle((Handle) hGlobals);
  933.     
  934.     // clear out our globals - to avoid double disposes
  935.     SetMessageHandlerInstanceContext(nil);
  936.  
  937.     return(noErr);
  938.     
  939.     
  940. } // SD_ShutDown
  941.  
  942. //<FF>
  943. /* ------------------------------------------------------------------------------------    */
  944. OSErr    SD_DefaultPrinter(gxPrinter thePrinter)
  945. /*
  946.     This call is made to setup the default printer object.  The job of the
  947.     specific driver is to add in any viewDevices that it wishes applications
  948.     to be able to format specifically for.
  949. */
  950. {
  951.     OSErr            anErr;
  952.     gxViewDevice    vd;
  953.     gxJob            theJob = GXGetJob();
  954.     
  955.     // add the standard viewDevices first
  956.     anErr = Forward_GXDefaultPrinter(thePrinter);
  957.     nrequire(anErr, DefaultPrinter);
  958.     
  959.     // add a 144 b/w viewDevice
  960.     vd = NewDeviceResolutionViewDevice();
  961.     {
  962.     gxSetColor        theColors[2];
  963.     gxSetColor        *pColor;
  964.     gxColorSet        theSet;
  965.     
  966.     pColor = &theColors[0];
  967.     
  968.     pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0xFFFF;
  969.     
  970.     pColor++;
  971.     pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;
  972.     
  973.     theSet = GXNewColorSet(gxRGBSpace, 2, theColors);
  974.     SetViewDeviceColorSet(vd, theSet);
  975.     GXDisposeColorSet(theSet);
  976.     }
  977.         
  978.     anErr = GXAddPrinterViewDevice(thePrinter, vd);
  979.     nrequire(anErr, FailedAddBWViewDevice);
  980.  
  981.     
  982.     // add a 144 color viewDevice with 8 colors in it
  983.     //
  984.     //    Color        Index        R            G            B
  985.     //    white        0            0xFFFF        0xFFFF        0xFFFF        
  986.     //    yellow        1            0xFFFF        0xFFFF        0x0000
  987.     //    magenta        2            0xFFFF        0x0000        0xFFFF
  988.     //    red            3            0xFFFF        0x0000        0x0000
  989.     //    cyan        4            0x0000        0xFFFF        0xFFFF
  990.     //    green        5            0x0000        0xFFFF        0x0000
  991.     //    blue        6            0x0000        0x0000        0xFFFF
  992.     //    black        7            0x0000        0x0000        0x0000
  993.     
  994.     if (PrinterHasColorRibbon(thePrinter))
  995.         {
  996.         gxSetColor        theColors[8];
  997.         gxSetColor        *pColor;
  998.         gxColorSet        theSet;
  999.         short            idx;
  1000.  
  1001.         vd = NewDeviceResolutionViewDevice();
  1002.         
  1003.         pColor = &theColors[0];
  1004.         for (idx = 0; idx < 8; ++idx)
  1005.             {
  1006.             // default the color to black
  1007.             pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;
  1008.             
  1009.             // and give it componants to go along with this index
  1010.             if (idx & 0x04)
  1011.                 pColor->rgb.red     = 0xFFFF;
  1012.             if (idx & 0x02)
  1013.                 pColor->rgb.green     = 0xFFFF;
  1014.             if (idx & 0x01)
  1015.                 pColor->rgb.blue     = 0xFFFF;
  1016.                 
  1017.             // move on to the next color
  1018.             ++pColor;
  1019.             }
  1020.         
  1021.         theSet = GXNewColorSet(gxRGBSpace, 8, theColors);
  1022.         SetViewDeviceColorSet(vd, theSet);
  1023.         GXDisposeColorSet(theSet);
  1024.  
  1025.         anErr = GXAddPrinterViewDevice(thePrinter, vd);
  1026.         nrequire(anErr, FailedAddColorViewDevice);
  1027.         }
  1028.     
  1029.     /* Only if we are the output printer (not the formatting printer) */
  1030.     if (GXGetJobPrinter(theJob) == GXGetJobOutputPrinter(theJob)) {
  1031.         Collection            jobCollection = GXGetJobCollection(GXGetJob());
  1032.         Handle                 jobQualitySettingsHdl;    
  1033.         gxQualityInfo        *qualitySettings;
  1034.         Ptr                    p;
  1035.         Str255                bestString, roughString;
  1036.  
  1037.         // read in our quality mode strings
  1038.         {
  1039.         short    curResFile = CurResFile();
  1040.         
  1041.         UseResFile(GXGetMessageHandlerResFile());
  1042.         
  1043.         GetIndString( bestString, kNewQualityID, kBestString);
  1044.         GetIndString( roughString, kNewQualityID, kRoughString);
  1045.         UseResFile(curResFile);
  1046.         }
  1047.         
  1048.         jobQualitySettingsHdl = NewHandle(0);
  1049.         anErr = MemError();
  1050.         nrequire(anErr, FailedNewHandle);
  1051.  
  1052.         anErr = GetCollectionItemHdl (     jobCollection,
  1053.                                         gxQualityTag,
  1054.                                         gxPrintingTagID,
  1055.                                         jobQualitySettingsHdl );
  1056.  
  1057.         if (anErr == noErr) 
  1058.             {    /* Check for proper structure -- count as not found if different */
  1059.             HLockHi(jobQualitySettingsHdl);
  1060.  
  1061.             qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
  1062.             p = qualitySettings->qualityNames;
  1063.  
  1064.             if (qualitySettings->disableQuality) 
  1065.                 anErr = collectionItemNotFoundErr;
  1066.             else if (qualitySettings->qualityCount != 2)
  1067.                 anErr = collectionItemNotFoundErr;
  1068.             else if (! IUEqualString((unsigned char const *) p, bestString))
  1069.                 anErr = collectionItemNotFoundErr;
  1070.             else if (! IUEqualString((unsigned char const *) (p + p[0] + 1), roughString))
  1071.                 anErr = collectionItemNotFoundErr;
  1072.  
  1073.             HUnlock(jobQualitySettingsHdl);
  1074.             }
  1075.  
  1076.         if (anErr == collectionItemNotFoundErr) 
  1077.             {
  1078.             Size            count;
  1079.  
  1080.             /* Create the proper quality item */
  1081.             SetHandleSize(jobQualitySettingsHdl,(sizeof(gxQualityInfo) + bestString[0] + roughString[0] + 2 ));
  1082.             anErr = MemError();
  1083.             nrequire( anErr, FailedSetHandleSize );
  1084.                 
  1085.             qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
  1086.             
  1087.             qualitySettings->disableQuality = false;
  1088.             qualitySettings->defaultQuality = 1;
  1089.             qualitySettings->currentQuality = 1;
  1090.             qualitySettings->qualityCount = 2;
  1091.  
  1092.             count = bestString[0]+1;
  1093.             p = qualitySettings->qualityNames;
  1094.             BlockMove( bestString, p, count );
  1095.  
  1096.             p += count;
  1097.             BlockMove( roughString, p, roughString[0]+1 );
  1098.  
  1099.             /* Add the proper quality item */
  1100.             anErr = AddCollectionItemHdl (     jobCollection,
  1101.                                             gxQualityTag,
  1102.                                             gxPrintingTagID,
  1103.                                             jobQualitySettingsHdl );
  1104.  
  1105.             /* Make it vilatile by driver */
  1106.             if (anErr == noErr)
  1107.                 (void) SetCollectionItemInfo(jobCollection, gxQualityTag, gxPrintingTagID, 0x0000FFFF, gxVolatileOutputDriverCategory);
  1108.  
  1109.             }
  1110.         
  1111. FailedSetHandleSize:
  1112.         DisposHandle(jobQualitySettingsHdl);
  1113.     }
  1114. FailedNewHandle:
  1115.     
  1116.     ncheck(noErr);
  1117.     return(noErr);
  1118.     
  1119.     
  1120.     
  1121. // EXCEPTION HANDLING
  1122. FailedAddColorViewDevice:
  1123. FailedAddBWViewDevice:
  1124.     GXDisposeViewDevice(vd);
  1125.     
  1126. DefaultPrinter:
  1127.     return(anErr);
  1128.     
  1129. } // SD_DefaultPrinter
  1130.  
  1131. //<FF>
  1132. /* ------------------------------------------------------------------------------------    */
  1133.  
  1134. OSErr SD_DefaultFormat(gxFormat theFormat)
  1135. {
  1136.     OSErr                anErr;
  1137.     Handle                 jobQualitySettingsHdl;    
  1138.     
  1139.     anErr = Forward_GXDefaultFormat(theFormat);
  1140.     
  1141.     // now, if the application has set up a special formatting mode, we need to update
  1142.     // the quality mode collection item (and any private ones we use)
  1143.     if (anErr == noErr)
  1144.         {
  1145.         gxPoint                dpiPoint;
  1146.         gxMapping            vdMapping;
  1147.         gxViewDevice        selectedDevice = GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 0);
  1148.         
  1149.         dpiPoint.x = ff(72);
  1150.         dpiPoint.y = ff(72);
  1151.  
  1152.         if (selectedDevice != GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 1) )
  1153.             {
  1154.             GXGetViewDeviceMapping(selectedDevice, &vdMapping);
  1155.             MapPoints(&vdMapping, 1, &dpiPoint);
  1156.             
  1157.             {
  1158.             Collection            jobCollection = GXGetJobCollection(GXGetJob());
  1159.             gxQualityInfo        *qualitySettings;
  1160.     
  1161.             jobQualitySettingsHdl = NewHandle(0);
  1162.             anErr = MemError();
  1163.             nrequire(anErr, FailedNewHandle);
  1164.  
  1165.             anErr = GetCollectionItemHdl (     jobCollection,
  1166.                                                 gxQualityTag,
  1167.                                                  gxPrintingTagID,
  1168.                                                jobQualitySettingsHdl );
  1169.  
  1170.             nrequire(anErr, FailedGetCollectionItemHdl);
  1171.  
  1172.             qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
  1173.  
  1174.             qualitySettings->currentQuality = 
  1175.                 (dpiPoint.y > ff(100)) ? (qualitySettings->qualityCount-1) : 0;
  1176.  
  1177.             anErr = AddCollectionItemHdl (     jobCollection,
  1178.                                             gxQualityTag,
  1179.                                             gxPrintingTagID,
  1180.                                             jobQualitySettingsHdl );
  1181.                                                  
  1182.             DisposHandle(jobQualitySettingsHdl);
  1183.             }
  1184.  
  1185.         
  1186.             if (anErr == noErr)
  1187.                 {
  1188.                 long    formatOptions;
  1189.                 
  1190.                 // turn off super-res
  1191.                 formatOptions = 0;
  1192.                 anErr = AddCollectionItem(GXGetFormatCollection(theFormat), 
  1193.                     DriverCreator, 0,
  1194.                     sizeof(formatOptions),
  1195.                     &formatOptions);
  1196.                 }
  1197.             }
  1198.         }
  1199.  
  1200. FailedNewHandle:        
  1201.     ncheck(anErr);
  1202.     return(anErr);
  1203.  
  1204. FailedGetCollectionItemHdl:
  1205.     DisposHandle(jobQualitySettingsHdl);
  1206.     return(anErr);
  1207.     
  1208. } // SD_DefaultFormat
  1209.  
  1210. //<FF>
  1211. /* ------------------------------------------------------------------------------------    */
  1212. OSErr SD_DefaultJob()
  1213. /*
  1214.     We override this message to add our default - highest res possible
  1215. */
  1216. {
  1217.     OSErr    anErr;
  1218.     
  1219.     anErr = Forward_GXDefaultJob();
  1220.     if (anErr == noErr)
  1221.         {
  1222.         long        imagewriterOptions = kSuperRes;
  1223.         
  1224.         anErr = AddCollectionItem(GXGetJobCollection(GXGetJob()), 
  1225.                     DriverCreator,
  1226.                     0,
  1227.                     sizeof(imagewriterOptions),
  1228.                     &imagewriterOptions);
  1229.                     
  1230.         }
  1231.  
  1232.  
  1233.     return(anErr);
  1234.     
  1235. } // SD_DefaultJob
  1236.  
  1237. /* ------------------------------------------------------------------------------------    */
  1238. OSErr SD_OpenConnection(void)
  1239. /*
  1240.     The OpenConnection message is sent in order to open the connection to the device.
  1241. */
  1242. {
  1243.     OSErr    anErr;
  1244.     SpecGlobalsHdl    hGlobals = (SpecGlobalsHdl)GetMessageHandlerInstanceContext();
  1245.     
  1246.     // how to process idle events
  1247.     (**hGlobals).idleError         = noErr;
  1248.     (**hGlobals).idleQuery         = false;
  1249.     (**hGlobals).idleTimeout     = 0;
  1250.     (**hGlobals).timeoutPending = false;
  1251.     
  1252.     // first, open the connection the standard way
  1253.     anErr = Forward_GXOpenConnection();
  1254.     nrequire(anErr, OpenConnection);
  1255.     
  1256.     // then, bring the configuration file up to date
  1257.     anErr = UpdateConfiguration();
  1258.     nrequire(anErr, UpdateConfiguration);
  1259.     
  1260.     return(noErr);
  1261.     
  1262. // EXCEPTION HANDLING
  1263. UpdateConfiguration:
  1264.     GXCleanupOpenConnection();
  1265.     
  1266. OpenConnection:
  1267.  
  1268.     return(anErr);
  1269.     
  1270. } // SD_OpenConnection
  1271.  
  1272. /* ------------------------------------------------------------------------------------    */
  1273. OSErr SD_CloseConnection(void)
  1274. {
  1275.     unsigned short    statusReturn;
  1276.     OSErr            anErr, anErr2;
  1277.     SpecGlobalsHdl    hGlobals = (SpecGlobalsHdl)GetMessageHandlerInstanceContext();
  1278.     ResType            commType = (**hGlobals).commType;
  1279.  
  1280.     if (commType == 'PPTL')
  1281.         {
  1282.         // flush out all data so that we can query the printer properly    one last time
  1283.         anErr = Send_GXWriteData(nil, 0);
  1284.         nrequire(anErr, Send_GXWriteData1);
  1285.         
  1286.         // for PAP: bring the configuration file up to date & check that the printer is online
  1287.         anErr2 = UpdateConfiguration();
  1288.         if (anErr == noErr) anErr = anErr2;
  1289.         }
  1290.     else
  1291.         {
  1292.         // for serial: flush out all data so that we can query the printer properly    one last time
  1293.         anErr = Send_GXWriteData(nil, 0);
  1294.         nrequire(anErr, Send_GXWriteData2);
  1295.  
  1296.         // one last time check up on printer status 
  1297.         if ((**hGlobals).isImageWriterII)
  1298.             {
  1299.             anErr2 = FetchStatusString(&statusReturn, false, true);
  1300.             if (anErr == noErr) anErr = anErr2;
  1301.             }
  1302.         }
  1303.     
  1304. Send_GXWriteData2:
  1305. Send_GXWriteData1:
  1306. FetchStatusString:
  1307.     // close the connection the standard way
  1308.     anErr2 = Forward_GXCloseConnection();
  1309.     if (anErr == noErr) anErr = anErr2;
  1310.         
  1311.     return(anErr);
  1312.     
  1313. } // SD_CloseConnection
  1314.  
  1315. /* ------------------------------------------------------------------------------------    */
  1316. OSErr SD_JobIdle()
  1317. {
  1318.     OSErr            anErr = noErr;
  1319.     SpecGlobalsHdl    hGlobals = (SpecGlobalsHdl)GetMessageHandlerInstanceContext();
  1320.     SpecGlobalsPtr    pGlobals;
  1321.     
  1322.     pGlobals = *hGlobals;
  1323.     if ( (pGlobals->idleQuery) && (pGlobals->commType == 'PPTL') )
  1324.         {
  1325.         unsigned short    statusReturn;
  1326.  
  1327.         pGlobals->idleQuery = false;
  1328.         
  1329.         anErr = FetchStatusString(&statusReturn, true, true);
  1330.         nrequire(anErr, FetchStatusString);
  1331.  
  1332.         anErr = Forward_GXJobIdle();
  1333.  
  1334.         // EXCEPTION HANDLING
  1335.         FetchStatusString:
  1336.             pGlobals = *hGlobals;
  1337.             pGlobals->idleQuery = true;
  1338.         }
  1339.     else    
  1340.         anErr = Forward_GXJobIdle();
  1341.     
  1342.     // if we continue looping here too long during the initial query -- give the user
  1343.     // a chance to bail or correct the problem
  1344.     pGlobals = *hGlobals;
  1345.     if ( (!(pGlobals->timeoutPending)) && (pGlobals->idleTimeout != 0) )
  1346.         {
  1347.         if (TickCount() > pGlobals->idleTimeout)
  1348.             {
  1349.             gxStatusRecord        theStat;
  1350.             gxStatusRecord        *pStat = &theStat;
  1351.             
  1352.             pStat->statusOwner    = 'drvr';
  1353.             pStat->statResId     = kDriverStatus;        
  1354.             pStat->statResIndex = kCheckOnline;            
  1355.             pStat->bufferLen      = 0;
  1356.             pStat->dialogResult = 0;
  1357.                         
  1358.             // tell the user to check the printer
  1359.             pGlobals->timeoutPending = true;
  1360.             (void) GXAlertTheUser(pStat);
  1361.             pGlobals = *hGlobals;
  1362.             pGlobals->timeoutPending = false;
  1363.                 
  1364.             // based on the user's response cancel
  1365.             switch (pStat->dialogResult)
  1366.                 {
  1367.                 case ok:
  1368.                     pGlobals->idleTimeout = TickCount() + kQueryTimeout;
  1369.                     break;
  1370.                     
  1371.                 case cancel:
  1372.                     pGlobals->idleError = gxPrUserAbortErr;
  1373.                     break;
  1374.                     
  1375.                 case 3:
  1376.                     pGlobals->idleError = kPutJobOnHoldErr;
  1377.                     break;
  1378.                 }
  1379.  
  1380.             // display "sending data to the printer" message
  1381.             if (anErr == noErr)
  1382.                 anErr = GXReportStatus(kDriverStatus, kSendingData);
  1383.             }
  1384.         }
  1385.         
  1386.     if (anErr == noErr)
  1387.         anErr = pGlobals->idleError;
  1388.         
  1389.     return(anErr);
  1390.     
  1391. } // SD_JobIdle
  1392.  
  1393. /* ------------------------------------------------------------------------------------    */
  1394. OSErr SD_FreeBuffer(gxPrintingBuffer * theBuffer)
  1395. {
  1396.     OSErr            anErr = noErr;
  1397.     OSErr            firstError = noErr;
  1398.     SpecGlobalsHdl    hGlobals = (SpecGlobalsHdl)GetMessageHandlerInstanceContext();
  1399.     
  1400.  
  1401.     if ((**hGlobals).commType == 'PPTL')
  1402.         {
  1403.         unsigned short    statusReturn;
  1404.  
  1405.         anErr = FetchStatusString(&statusReturn, true, true);
  1406.         nrequire(anErr, FetchStatusString);
  1407.         }
  1408.         
  1409.     do
  1410.         {
  1411.         // we can idle query now if we need to    
  1412.         (**hGlobals).idleQuery = true;
  1413.  
  1414.         // try to send the buffer again
  1415.         anErr = Forward_GXFreeBuffer(theBuffer);
  1416.         if (firstError == noErr)
  1417.             firstError = anErr;
  1418.     
  1419.         (**hGlobals).idleQuery = false;
  1420.  
  1421.         // timeout dialog!
  1422.         if (anErr == gxAioTimeout)
  1423.             {
  1424.             gxStatusRecord        theStat;
  1425.             gxStatusRecord        *pStat = &theStat;
  1426.             
  1427.             pStat->statusOwner    = 'drvr';
  1428.             pStat->statResId     = kDriverStatus;        
  1429.             pStat->statResIndex = kCheckOnline;            
  1430.             pStat->bufferLen      = 0;
  1431.             pStat->dialogResult = 0;
  1432.                         
  1433.             // tell the user to check the printer
  1434.             (void) GXAlertTheUser(pStat);
  1435.                 
  1436.             // based on the user's response cancel
  1437.             switch (pStat->dialogResult)
  1438.                 {
  1439.                 case ok:
  1440.                     anErr = gxAioTimeout;
  1441.                     break;
  1442.                     
  1443.                 case cancel:
  1444.                     anErr = gxPrUserAbortErr;
  1445.                     break;
  1446.                     
  1447.                 case 3:
  1448.                     anErr = kPutJobOnHoldErr;
  1449.                     break;
  1450.                 }
  1451.             }
  1452.             
  1453.         } while (anErr == gxAioTimeout);
  1454.     
  1455.     // put down the timeout dialog, if we ever put one up
  1456.     if (firstError != noErr)
  1457.         (void) GXReportStatus(kDriverStatus, kSendingData);
  1458.  
  1459.     // error to return from next idle
  1460.     (**hGlobals).idleError = anErr;
  1461.     
  1462. FetchStatusString:        
  1463.     return(anErr);
  1464.     
  1465. } // SD_FreeBuffer
  1466.  
  1467. /* ------------------------------------------------------------------------------------    */
  1468. OSErr SD_DumpBuffer(gxPrintingBuffer * theBuffer)
  1469. {
  1470.     OSErr    anErr;
  1471.     SpecGlobalsHdl    hGlobals = (SpecGlobalsHdl)GetMessageHandlerInstanceContext();
  1472.         
  1473.     if ((**hGlobals).commType == 'PPTL')
  1474.         {
  1475.         unsigned short    statusReturn;
  1476.         anErr = FetchStatusString(&statusReturn, true, true);
  1477.         nrequire(anErr, FetchStatusString);
  1478.         }
  1479.     anErr = Forward_GXDumpBuffer(theBuffer);
  1480.  
  1481. FetchStatusString:        
  1482.     return(anErr);
  1483.     
  1484. } // SD_DumpBuffer
  1485.  
  1486. /* ------------------------------------------------------------------------------------    */
  1487. OSErr SD_StartSendPage(gxFormat pageFormat)
  1488. /*
  1489.     The StartSendPage message is sent just before the page begins to be rendered.
  1490.     
  1491.     Note that the StartSendPage message will not be sent until imaging/communication
  1492.     time, so that user interaction alerts are considered okay here
  1493. */
  1494. {
  1495.     OSErr                        anErr = noErr;
  1496.     gxJob                        theJob = GXGetJob();
  1497.     Collection                    jobCollection;
  1498.     gxPaperType                    thePaperType;
  1499.     gxTrayFeedInfo                trayFeedInfo;
  1500.     long                        itemSize = sizeof(trayFeedInfo);
  1501.     ResType                        commType;
  1502.     unsigned short                statusReturn;
  1503.     
  1504.     check(theJob);
  1505.     jobCollection = GXGetJobCollection(theJob);
  1506.     check(jobCollection);
  1507.     
  1508.     // cache communications type
  1509.     commType = (**(SpecGlobalsHdl)GetMessageHandlerInstanceContext()).commType;
  1510.     if (commType == 'PPTL')
  1511.         {
  1512.         anErr = FetchStatusString(&statusReturn, true, true);
  1513.         nrequire(anErr, FetchStatusString);
  1514.         }
  1515.     else
  1516.         statusReturn = 0;
  1517.         
  1518.     // check to see if this particular page is to be manually fed
  1519.     anErr = GetCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
  1520.     nrequire(anErr, FailedGetCollectionItem);
  1521.             
  1522.     // manual feed or out of paper?  Time to ask the user what to do
  1523.     if     (     trayFeedInfo.manualFeedThisPage
  1524.         ||  ( ( (statusReturn & kOutOfPaperMask) != 0 ) )
  1525.         )
  1526.         {
  1527.         // Wait for all IO to complete, so that we can correctly tell the user what to do.
  1528.         // Since the WriteData message makes sure all data is flushed before performing the
  1529.         // IO, this call insures that pending IO is complete.
  1530.         anErr = Send_GXWriteData(nil, 0);
  1531.         nrequire(anErr, FlushAllData);
  1532.  
  1533.  
  1534.         // then, conduct the alert with the user
  1535.         {
  1536.         gxStatusRecord        *pStat;
  1537.         
  1538.         // make a status record containing the request to the user - note that 
  1539.         // we have to make room for ManualFeedRecord OR OutOfPaperRecord, but manual is bigger
  1540.         pStat = (gxStatusRecord *)NewPtrClear(sizeof(gxStatusRecord)  + sizeof(gxManualFeedRecord));
  1541.         anErr = MemError();
  1542.         nrequire(anErr, NewPtrClear);
  1543.                 
  1544.         pStat->statusOwner    = 'univ';
  1545.         pStat->statResId     = gxUnivAlertStatusResourceId;    // we use the built-in status for this
  1546.         pStat->dialogResult = 0;
  1547.         
  1548.         if (trayFeedInfo.manualFeedThisPage)
  1549.             {
  1550.             gxManualFeedRecord    *pFeed;
  1551.             
  1552.             pStat->statResIndex = gxUnivManualFeedIndex;            // status meaning "manual feed alert"
  1553.             pStat->bufferLen      = sizeof(gxManualFeedRecord);
  1554.             pFeed = (gxManualFeedRecord*)&pStat->statusBuffer;
  1555.         
  1556.             // we can switch to autofeed if we want - and tell the user what kind of paper to load in
  1557.             pFeed->canAutoFeed = true;
  1558.             GXGetPaperTypeName(thePaperType = GXGetFormatPaperType(pageFormat), pFeed->paperTypeName);
  1559.             }
  1560.         else
  1561.             {
  1562.             gxOutOfPaperRecord    *pOut;
  1563.             
  1564.             pStat->statResIndex = gxUnivOutOfPaperIndex;            // status meaning "manual feed alert"
  1565.             pStat->bufferLen      = sizeof(gxOutOfPaperRecord);
  1566.             
  1567.             pOut = (gxOutOfPaperRecord*)&pStat->statusBuffer;
  1568.             GXGetPaperTypeName(GXGetFormatPaperType(pageFormat), pOut->paperTypeName);
  1569.             }
  1570.             
  1571.         // keep sending the user the alert until either
  1572.         //  a) the problem resolves itself
  1573.         //  b) the user responds via the dialog
  1574.         //  c) some other (fatal) error happens
  1575.         do
  1576.             {
  1577.             
  1578.             // tell the user
  1579.             anErr = GXAlertTheUser(pStat);
  1580.             
  1581.             // if the paper got suddenly loaded, do an OK
  1582.             if (commType == 'PPTL')
  1583.                 {
  1584.                 (void) FetchStatusString(&statusReturn, true, true);
  1585.                 if ((statusReturn & kOutOfPaperMask) == 0)
  1586.                     {
  1587.                     pStat->dialogResult = ok;
  1588.                     anErr = noErr;
  1589.                     }
  1590.                 }
  1591.                 
  1592.             } while ((anErr == noErr) && (pStat->dialogResult == 0));
  1593.  
  1594.         // based on the user's response, continue, cancel, or switch to auto feed
  1595.         switch ( pStat->dialogResult )
  1596.             {
  1597.             case ok:
  1598.                 // paper is loaded
  1599.                 break;
  1600.                 
  1601.             case cancel:
  1602.                 // user wishes to stop the printing process
  1603.                 anErr = gxPrUserAbortErr;
  1604.                 break;
  1605.                 
  1606.             case gxAutoFeedButtonId:
  1607.                 // do rest of job with auto feed
  1608.                 
  1609.                 {
  1610.                 gxPaperFeedInfo paperFeed;
  1611.                 
  1612.                 /* Update for job */
  1613.                 paperFeed.autoFeed = true;
  1614.                 (void) AddCollectionItem(jobCollection, gxPaperFeedTag, gxPrintingTagID, sizeof(paperFeed), &paperFeed);
  1615.                 }
  1616.                 
  1617.                 /* Update as it may be reused */
  1618.                 trayFeedInfo.manualFeedThisPage = false;    /* Other trayInfo fields are still valid */
  1619.                 (void) AddCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, sizeof(trayFeedInfo), &trayFeedInfo);
  1620.                 
  1621.                 /* Can pass paper type reference as this IS device communication time */
  1622.                 anErr = Send_GXCheckStatus((Ptr) &thePaperType, sizeof(thePaperType), 0, 'univ');
  1623.                 ncheck(anErr);
  1624.                 
  1625.                 /* No need to reset tray from gxTrayFeedInfo.feedTrayIndex as there is only one tray! */
  1626.                 break;
  1627.                 
  1628.             } // switch
  1629.             
  1630.             
  1631.         // done with the status now
  1632.         DisposPtr((Ptr) pStat);
  1633.         }
  1634.             
  1635.         } // if manual feed job
  1636.         
  1637.     // display "sending data to the printer" message
  1638.     if (anErr == noErr)
  1639.         anErr = GXReportStatus(kDriverStatus, kSendingData);
  1640.         
  1641.     nrequire(anErr, FailedWaitForPaper);
  1642.         
  1643.     // continue with the standard starting of the page
  1644.     anErr = Forward_GXStartSendPage(pageFormat);
  1645.         
  1646.         
  1647. // FALL THROUGH AND HANDLE EXCEPTIONS
  1648.  
  1649. FailedWaitForPaper:
  1650. NewPtrClear:
  1651. FlushAllData:
  1652. FailedGetCollectionItem:
  1653. FetchStatusString:
  1654.     return(anErr);
  1655.     
  1656. } // SD_StartSendPage
  1657.  
  1658. /* ------------------------------------------------------------------------------------    */
  1659. OSErr SD_FinishSendPage()
  1660. {
  1661.     OSErr        anErr = noErr;
  1662.     Str63        formLength;            // should be more than big enough for form skipping
  1663.     char        len = 0;
  1664.  
  1665.     // we may have issued line feeds RIGHT up to the end of the page.  If
  1666.     // we do that and then issue a form feed, we'll kick out a blank page.
  1667.     // to avoid that, we back up a tad and then let the normal form feed
  1668.     // go through.  Option 2 would be to track each and every motion control
  1669.     // we send to the printer -- but that's more work than this.  In addition,
  1670.     // this method makes sure we are synced up exactly to the hardware
  1671.     formLength[len++] = ESCAPE;
  1672.     formLength[len++] = 'T';
  1673.     formLength[len++] = '0';
  1674.     formLength[len++] = '1';
  1675.     formLength[len++] = ESCAPE;
  1676.     formLength[len++] = 'r';
  1677.     formLength[len++] = 0x0A;
  1678.     
  1679.     // reset to forward motion for the form feed
  1680.     formLength[len++] = ESCAPE;
  1681.     formLength[len++] = 'f';
  1682.     
  1683.     anErr = Send_GXBufferData((char *) &formLength[0], len, gxNoBufferOptions );
  1684.     nrequire(anErr, Send_GXBufferData);
  1685.     
  1686.     // Default implementation provides the actual form feed
  1687.     anErr = Forward_GXFinishSendPage();
  1688.     
  1689. // FALL THROUGH EXCEPTION HANDLING
  1690. Send_GXBufferData:
  1691.  
  1692.     return(anErr);
  1693.     
  1694. } // SD_FinishSendPage
  1695.  
  1696. /* ------------------------------------------------------------------------------------    */
  1697. OSErr SD_JobFormatDialog(gxDialogResult*    theResult)
  1698. /*
  1699.     This message is sent in response to the user's request to put up a formatting dialog
  1700. */
  1701. {
  1702.     OSErr                     anErr;
  1703.     gxJobFormatModeTableHdl    theJobFormatModeList;
  1704.     long                    i;
  1705.     gxJob                     theJob = GXGetJob();
  1706.     
  1707.     // set up the JobFormatMode information
  1708.     
  1709.     anErr = GXGetAvailableJobFormatModes(&theJobFormatModeList);
  1710.     if ((!anErr) && (theJobFormatModeList))
  1711.         {
  1712.         for (i = 0; i <= (*theJobFormatModeList)->numModes - 1; ++i) 
  1713.             {
  1714.             if ((*theJobFormatModeList)->modes[i] == gxTextJobFormatMode) 
  1715.                 {
  1716.                 GXSetPreferredJobFormatMode(gxTextJobFormatMode, false);
  1717.                 break;
  1718.                 }
  1719.             }
  1720.         DisposHandle((Handle)theJobFormatModeList);
  1721.         }
  1722.         
  1723.     // do the normal dialogs after handling the job format mode stuff
  1724.     return(Forward_GXJobDefaultFormatDialog(theResult));
  1725.     
  1726. } // SD_JobFormatModeQuery
  1727.  
  1728. /* ------------------------------------------------------------------------------------    */
  1729. OSErr SD_JobFormatModeQuery(    gxQueryType        theQuery,
  1730.                                 void*            srcData,
  1731.                                 void*            dstData)
  1732. /*
  1733.     This message is sent to find out information about the current job format mode.
  1734. */
  1735. {
  1736.     OSErr        anErr = noErr;
  1737.     Handle        theFonts;
  1738.     Handle        theStyles;
  1739.     
  1740.     check(dstData != nil);
  1741.     
  1742.     // What type of query is being requested?
  1743.     switch(theQuery) 
  1744.     {
  1745.         case gxSetStyleJobFormatCommonStyleQuery:
  1746.         {
  1747.             char                *pStyleName;
  1748.  
  1749.             // Fetch the list of supported styles
  1750.             
  1751.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
  1752.             require(anErr == noErr, FailedToLoadStyles1);
  1753.             
  1754.             HNoPurge(theStyles);
  1755.             HLock(theStyles);
  1756.             
  1757.             // Determine which style is being referenced and set the corresponding style (only 2 styles
  1758.             // are currently supported)
  1759.             
  1760.             if (**((short **) theStyles) == 2)    //    T => We have the correct number of styles
  1761.             {
  1762.                 char        whichFace = 0;
  1763.                 
  1764.                 pStyleName = ((char *) *theStyles) + sizeof(short); 
  1765.                 
  1766.                 if ( IUCompString((unsigned char const *) pStyleName, srcData) == 0 )    //    T => They want bold face
  1767.                 {
  1768.                     whichFace = bold;
  1769.                 }
  1770.                 else
  1771.                 {
  1772.                     // Point to the next name in the list
  1773.                     pStyleName += *pStyleName + 1;
  1774.  
  1775.                     if ( IUCompString((unsigned char const *) pStyleName, srcData) == 0 )    //    T => They want underline face
  1776.                     {
  1777.                         whichFace = underline;
  1778.                     }
  1779.                 }
  1780.  
  1781.                 //    If the client specified a valid face, set it now
  1782.                 if (whichFace != 0)
  1783.                 {
  1784.                     SetStyleCommonFace((gxStyle) dstData, GetStyleCommonFace((gxStyle) dstData) | whichFace);
  1785.                 }
  1786.             }
  1787.             // else - something is wrong with our resource
  1788.             
  1789.             // Dump the temporary handle
  1790.             DisposHandle(theStyles);
  1791.             
  1792.             break;
  1793.         }
  1794.             
  1795.         case gxGetJobFormatFontCommonStylesQuery:
  1796.         {
  1797.             short                numStyles;
  1798.             short                i;
  1799.             char                *pStyleName;
  1800.  
  1801.             // Fetch the list of supported styles
  1802.             
  1803.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
  1804.             require(anErr == noErr, FailedToLoadStyles2);
  1805.             
  1806.             HNoPurge(theStyles);
  1807.             HLock(theStyles);
  1808.             
  1809.             // Determine the number of styles in the list
  1810.             numStyles = **((short **) theStyles);
  1811.  
  1812.             if (*(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on the styles
  1813.                 SetHandleSize(*(Handle *)dstData, sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
  1814.             else
  1815.                 *(Handle *)dstData = NewHandle(sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
  1816.             
  1817.             anErr = MemError();
  1818.             require(anErr == noErr, StyleTableResizeFailed);
  1819.             
  1820.             // Now extract the name of each of the supported fonts
  1821.             
  1822.             for (i = 1, pStyleName = ((char *) *theStyles) + sizeof(short); i <= numStyles; ++i, pStyleName += *pStyleName + 1)
  1823.             {
  1824.                 BlockMove(pStyleName, (*((gxStyleNameTableHdl) *(Handle *)dstData))->styleNames[i - 1], *pStyleName + 1);
  1825.             }
  1826.             
  1827.             (*((gxStyleNameTableHdl) *(Handle *)dstData))->numStyleNames = numStyles;
  1828.             
  1829.             // Dump the temporary handle
  1830.             DisposHandle(theStyles);
  1831.             
  1832.             break;
  1833.         }
  1834.             
  1835.         case gxGetJobFormatLineConstraintQuery:            //    This type of query is not supported
  1836.             if (*(Handle *)dstData != nil)
  1837.                 SetHandleSize(*(Handle *)dstData, 0);        // Don't return any data
  1838.             break;
  1839.             
  1840.         case gxGetJobFormatFontsQuery:
  1841.         {
  1842.             short                numFonts;
  1843.             short                i;
  1844.             char                *pFontName;
  1845.  
  1846.             // Fetch the list of supported fonts
  1847.             
  1848.             anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeFontsID, &theFonts);
  1849.             require(anErr == noErr, FailedToLoadFonts);
  1850.             
  1851.             HNoPurge(theFonts);
  1852.             HLock(theFonts);
  1853.             
  1854.             // Determine the number of fonts in the list
  1855.             numFonts = **((short **) theFonts);
  1856.  
  1857.             if (*(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on the fonts
  1858.                 SetHandleSize(*(Handle *)dstData, sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
  1859.             else
  1860.                 *(Handle *)dstData = NewHandle(sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
  1861.             
  1862.             anErr = MemError();
  1863.             require(anErr == noErr, FontTableResizeFailed);
  1864.             
  1865.             // Now generate a reference to each of the supported fonts
  1866.             
  1867.             for (i = 1, pFontName = ((char *) *theFonts) + sizeof(short); i <= numFonts; ++i, pFontName += *pFontName + 1)
  1868.             {
  1869.                 gxFont            thisFont;
  1870.                 gxFontTable        *pFontTable;
  1871.             
  1872.                 thisFont = FindPNameFont(gxFullFontName, (unsigned char const *) pFontName);
  1873.                 
  1874.                 pFontTable = *((gxFontTableHdl) *(Handle *)dstData);
  1875.                 pFontTable->fonts[i - 1] = thisFont;
  1876.             }
  1877.             
  1878.             (*((gxFontTableHdl) *(Handle *)dstData))->numFonts = numFonts;
  1879.             
  1880.             // Dump the temporary handle
  1881.             DisposHandle(theFonts);
  1882.  
  1883.             break;
  1884.         }
  1885.             
  1886.         case gxGetJobFormatFontConstraintQuery:
  1887.         {
  1888.             gxPositionConstraintTable        *pPositionTable;
  1889.             
  1890.             if ( *(Handle *)dstData != nil)    //    T => Resize the handle to hold info. on position constraints
  1891.                 SetHandleSize(*(Handle *)dstData, sizeof(gxPositionConstraintTable) + sizeof(Fixed));
  1892.             else
  1893.                 *(Handle *)dstData = NewHandle( sizeof(gxPositionConstraintTable) + sizeof(Fixed) );
  1894.             
  1895.             pPositionTable = *((gxPositionConstraintTableHdl) *(Handle *)dstData);
  1896.             
  1897.             pPositionTable->phase.x     = 0;                //    Start at the top left corner of the page
  1898.             pPositionTable->phase.y     = 0;
  1899.             pPositionTable->offset.x     = ff(12);        // Indent from the top left by a six lines per inch margin
  1900.             pPositionTable->offset.y     = ff(12);         
  1901.             pPositionTable->numSizes     = 2;                // Two font sizes supported
  1902.             pPositionTable->sizes[0]     = ff(10);         // 10 pitch
  1903.             pPositionTable->sizes[1]     = ff(12);         // 12 pitch
  1904.             
  1905.             break;
  1906.         }
  1907.     } // switch
  1908.     
  1909.     return(anErr);
  1910.     
  1911.  
  1912. /******* Clean-up *******/
  1913.  
  1914. StyleTableResizeFailed:
  1915.     DisposHandle((Handle) theStyles);
  1916.     return(anErr);
  1917.  
  1918. FontTableResizeFailed:
  1919.     DisposHandle((Handle) theFonts);
  1920.  
  1921. FailedToLoadStyles1:
  1922. FailedToLoadStyles2:
  1923. FailedToLoadFonts:
  1924.     return(anErr);
  1925.     
  1926. } // SD_JobFormatModeQuery
  1927.  
  1928. //<FF>
  1929. /* ------------------------------------------------------------------------------------    */
  1930. OSErr SD_SetupImageData(
  1931.     gxRasterImageDataHdl hImageData)        // raster image data stuff
  1932. /*
  1933.     This message is called to setup the constant data used for imaging the entire job.
  1934. */
  1935. {
  1936.  
  1937.     SpecGlobalsHdl                 hGlobals = GetMessageHandlerInstanceContext();
  1938.     OSErr                        anErr;
  1939.     gxRasterImageDataPtr        pImageData;
  1940.     Boolean                     isJobNotFinalQuality, isTextJobFormatMode;
  1941.     long                        imagewriterOptions;
  1942.     
  1943.     // do the default setup
  1944.     anErr = Forward_GXSetupImageData(hImageData);
  1945.     nrequire(anErr, Forward_GXSetupImageData);
  1946.     
  1947.     // test for 'final' quality mode
  1948.     isJobNotFinalQuality = !JobIsBest(&imagewriterOptions);
  1949.     
  1950.     // test for textJobFormatMode
  1951.     isTextJobFormatMode = ( GXGetJobFormatMode( GXGetJob() ) == gxTextJobFormatMode);
  1952.             
  1953.     // if the job is not final quality or using textJobFormatMode, downgrade the imaging data to our lower quality
  1954.     if (isJobNotFinalQuality  ||  isTextJobFormatMode)
  1955.         {
  1956.         // ROUGH OR TEXT MODE
  1957.         
  1958.         // dereference for size and speed    
  1959.         pImageData = *hImageData;
  1960.                 
  1961.         // image at 80 or 72 dpi
  1962.         if (imagewriterOptions & kSuperRes)
  1963.             pImageData->hImageRes = ff(80);
  1964.         else
  1965.             pImageData->hImageRes = ff(72);
  1966.         pImageData->vImageRes = ff(72);
  1967.         
  1968.         // textJobFormatMode loads up the draft table, else setup halftones
  1969.         if (isTextJobFormatMode)
  1970.             {
  1971.             Handle            draftTable;
  1972.  
  1973.             anErr = Send_GXFetchTaggedDriverData('idft', gxPrintingDriverBaseID, &draftTable);
  1974.             nrequire(anErr, FailedToLoadDraftTable);
  1975.             
  1976.             // store away the draft table
  1977.             (**hGlobals).draftTable = draftTable;
  1978.  
  1979.             // Download something?    
  1980.             anErr = Send_GXFetchTaggedDriverData('idft', gxPrintingDriverBaseID+1, &draftTable);
  1981.             if (anErr == resNotFound)
  1982.                 {
  1983.                 draftTable = nil;
  1984.                 anErr = noErr;
  1985.                 }
  1986.             nrequire(anErr, GetDownloadTable);    
  1987.         
  1988.             if (draftTable)
  1989.                 {
  1990.                 HLock(draftTable);
  1991.                 anErr = Send_GXBufferData(*draftTable, GetHandleSize(draftTable), gxDontSplitBuffer);
  1992.                 DisposHandle(draftTable);
  1993.                 nrequire(anErr, SendDownloadTable);
  1994.                 }
  1995.             }
  1996.         else
  1997.             {            
  1998.             // use dither level that will look better at 72 dpi 
  1999.             // resolution than our default values (MAYBE: 4 is the default now anyway)
  2000.             pImageData->theSetup.planeSetup[0].planeHalftone.method = 4;
  2001.             
  2002.             // of course, turn off color matching when in non-final mode!
  2003.             pImageData->theSetup.planeSetup[0].planeProfile = nil;
  2004.             }
  2005.             
  2006.         if (isJobNotFinalQuality)
  2007.             {
  2008.             if (imagewriterOptions & kSuperRes)
  2009.                 {
  2010.                 // use bidirectional instead of unidirectional
  2011.                 // and also <esc>N instead of <esc>p for quality mode
  2012.                 pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+3;
  2013.                 }
  2014.             else
  2015.                 {
  2016.                 // use bidirectional instead of unidirectional
  2017.                 // and also <esc>n instead of <esc>p for quality mode
  2018.                 pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+2;
  2019.                 }
  2020.             }
  2021.         
  2022.         // packaging data
  2023.         pImageData->packagingInfo.headHeight         = 8;        // 8 pins (instead of 16)
  2024.         pImageData->packagingInfo.numberPasses         = 1;        // in 1 head pass (instead of 2)
  2025.         pImageData->packagingInfo.passOffset         = 0;        // with no space between passes
  2026.         }
  2027.     else
  2028.         {
  2029.         // FINAL QUALITY
  2030.         
  2031.         // dereference for size and speed    
  2032.         pImageData = *hImageData;
  2033.                 
  2034.         // image at 160 or 144 dpi
  2035.         if (imagewriterOptions & kSuperRes)
  2036.             {
  2037.             pImageData->hImageRes = ff(160);
  2038.             pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+1;
  2039.             }
  2040.         else
  2041.             {
  2042.             pImageData->hImageRes = ff(144);
  2043.             pImageData->packageControls.startPageStringID = gxPrintingDriverBaseID+0;
  2044.             }
  2045.         }
  2046.     
  2047.     // not a color ribbon?  Setup for black and white - do a B/W halftone rather than a dither
  2048.     if (!PrinterHasColorRibbon(GXGetJobOutputPrinter(GXGetJob())))
  2049.         {
  2050.         // dereference for size and speed    
  2051.         pImageData = *hImageData;
  2052.  
  2053.         // one plane, no color flags, move the halftone info up into correct position
  2054.         pImageData->theSetup.planes = 1;
  2055.         pImageData->theSetup.depth = 1;
  2056.         pImageData->packagingInfo.colorPasses = 1;
  2057.         pImageData->packagingInfo.packageOptions = 0;
  2058.         pImageData->theSetup.planeSetup[0].planeSpace = gxNoSpace;
  2059.         pImageData->theSetup.planeSetup[0].planeSet = nil;
  2060.         pImageData->theSetup.planeSetup[0].planeProfile = nil;
  2061.         pImageData->theSetup.planeSetup[0].planeOptions = gxDefaultOffscreen;
  2062.         pImageData->theSetup.planeSetup[0].planeHalftone.method = gxRoundDot;
  2063.         pImageData->theSetup.planeSetup[0].planeHalftone.tintSpace = gxRGBSpace;
  2064.         }
  2065.  
  2066.     return(noErr);
  2067.     
  2068. // EXCEPTION HANDLING
  2069. SendDownloadTable:
  2070. GetDownloadTable:
  2071.     DisposHandle((**hGlobals).draftTable);
  2072.     (**hGlobals).draftTable = nil;
  2073.     
  2074. FailedToLoadDraftTable:
  2075. Forward_GXSetupImageData:
  2076.     return(anErr);
  2077.     
  2078. } // SD_SetupImageData
  2079.  
  2080. /* ------------------------------------------------------------------------------------    */
  2081. OSErr SD_FetchDriverData(
  2082.     ResType            theType,
  2083.     short            theID,
  2084.     Handle*            theData)
  2085. {
  2086.  
  2087.     OSErr    anErr;
  2088.     
  2089.     anErr = Forward_GXFetchTaggedDriverData(theType, theID, theData);
  2090.     
  2091.     // do the translation at the proper DPI by modifying the old API
  2092.     // customization resource
  2093.     if ( (anErr   == noErr)    &&                 // got the resource okay
  2094.          (theType == 'cust')   &&                // it was a customization resource 
  2095.          (theID   == -8192)   )                    // with the old API id
  2096.         {
  2097.         long imagewriterOptions;
  2098.         
  2099.         if (!JobIsBest(&imagewriterOptions))
  2100.             {
  2101.             **((short**)theData)   = 72;
  2102.             **((short**)theData+1) = 72;
  2103.             }
  2104.         }
  2105.         
  2106.     return(anErr);
  2107.     
  2108. } // SD_FetchDriverData
  2109.  
  2110.  
  2111. /* ------------------------------------------------------------------------------------    */
  2112. OSErr SD_RenderPage(    gxFormat                theFormat,
  2113.                         gxShape                    thePage,
  2114.                         gxPageInfoRecord        *pageInfo,
  2115.                         gxRasterImageDataHdl    imageInfo)
  2116. /*
  2117.     The message sent to render an entire page.
  2118. */
  2119. {
  2120.  
  2121.     OSErr    theError = noErr;
  2122.  
  2123.     // if not text mode, do it the normal (raster) way
  2124.     if (GXGetJobFormatMode(GXGetJob()) != gxTextJobFormatMode) 
  2125.         {
  2126.         gxRectangle            paperSize;
  2127.         Str63                formLength;            // should be more than big enough for form skipping
  2128.         char                aNumber[8];
  2129.         char                len = 0;
  2130.         short                formLen;            // form length (in 144 dpi)
  2131.         short                i;
  2132.         
  2133.         
  2134.         // find out how big our paper is
  2135.         GXGetPaperTypeDimensions(GXGetFormatPaperType(theFormat), nil, &paperSize);
  2136.         
  2137.         // determine the left margin (in pixels)
  2138.         {
  2139.         SpecGlobalsHdl             hGlobals = GetMessageHandlerInstanceContext();
  2140.         SpecGlobalsPtr            pGlobals;
  2141.         gxRasterImageDataPtr    pImageData;
  2142.  
  2143.         check(hGlobals);
  2144.  
  2145.         // dereference for size and speed    
  2146.         pImageData     = *imageInfo;
  2147.         pGlobals = *hGlobals;
  2148.         paperSize.left += ff(18);        // ImageWriter's can't go tighter than .25 inch
  2149.         if (paperSize.left > 0)
  2150.             paperSize.left = 0;
  2151.         pGlobals->leftMargin     = FixedToInt(
  2152.                                     FixMul(-paperSize.left, 
  2153.                                         FixDiv(pImageData->hImageRes, ff(72))));
  2154.         
  2155.         // set this to be the top of form
  2156.         formLength[len++] = ESCAPE;
  2157.         formLength[len++] = 'v';
  2158.  
  2159.         // set the form length to be the size of the page iff ImageWriterII
  2160.         if (pGlobals->isImageWriterII)
  2161.             {
  2162.             formLength[len++] = ESCAPE;
  2163.             formLength[len++] = 'H';
  2164.             formLen = FixedToInt(FixMul(paperSize.bottom-paperSize.top, ff(2)) );    // length is set in 144 dpi
  2165.             NumToString(formLen, (unsigned char *) aNumber);
  2166.             for (i = 0; i < 4-aNumber[0]; ++i)
  2167.                 formLength[len++] = '0';
  2168.             for (i = 1; i <= aNumber[0]; ++i)
  2169.                 formLength[len++] = aNumber[i];
  2170.             }
  2171.         }
  2172.  
  2173.         // NOW: move over the top margin
  2174.         formLen = -FixedToInt( FixMul(paperSize.top, ff(2)) );
  2175.         
  2176.             // Forward line feed
  2177.             formLength[len++] = ESCAPE;
  2178.             formLength[len++] = 'f';
  2179.  
  2180.             // send multiples of 99
  2181.             if (formLen >= 99)
  2182.                 {
  2183.                 formLength[len++] = ESCAPE;
  2184.                 formLength[len++] = 'T';
  2185.                 formLength[len++] = '9';
  2186.                 formLength[len++] = '9';
  2187.                 while (formLen >= 99)
  2188.                     {
  2189.                     formLength[len++] = 0x0A;        // line feed
  2190.                     
  2191.                     formLen -= 99;
  2192.                     }
  2193.                 }
  2194.                 
  2195.             // send remaining line feeds
  2196.             if (formLen > 0)
  2197.                 {
  2198.                 formLength[len++] = ESCAPE;
  2199.                 formLength[len++] = 'T';
  2200.                 NumToString(formLen, (unsigned char *) aNumber);
  2201.                 if (aNumber[0] == 1)
  2202.                     {
  2203.                     formLength[len++] = '0';
  2204.                     formLength[len++] = aNumber[1];
  2205.                     }
  2206.                 else
  2207.                     {
  2208.                     formLength[len++] = aNumber[1];
  2209.                     formLength[len++] = aNumber[2];
  2210.                     }
  2211.                 formLength[len++] = 0x0A;        // line feed
  2212.                 }
  2213.  
  2214.  
  2215.         // we've got all of this data, now send it
  2216.         theError = Send_GXBufferData((char *) &formLength[0], len, gxNoBufferOptions );
  2217.         nrequire(theError, SetFormLength);        
  2218.                 
  2219.         // continue with normal rendering
  2220.         theError = Forward_GXRenderPage(theFormat, thePage, pageInfo, imageInfo);
  2221.         } 
  2222.     else 
  2223.         {
  2224.         theError = PrintPageInDraftMode(thePage, imageInfo);
  2225.         }
  2226.  
  2227. failed_WrongShape:
  2228. SetFormLength:
  2229.     return(theError);
  2230.     
  2231. } // SD_RenderPage
  2232.  
  2233.  
  2234. //<FF>
  2235. /* ------------------------------------------------------------------------------------    */
  2236. /*    SPECIFIC DRIVER RASTER OVERRIDES                                                    */
  2237. /* ------------------------------------------------------------------------------------    */
  2238. OSErr SD_LineFeed (
  2239.     long *lineFeedSize,                         // amount to line feed by
  2240.     Ptr buffer, unsigned long    * bufferPos,     // data goes here
  2241.     gxRasterImageDataHdl hImageData)            // raster image data stuff
  2242. /*
  2243.     Message is sent to output paper advance commands to the printer
  2244. */
  2245. {
  2246.  
  2247.     OSErr    anErr;
  2248.     Boolean    amLowRes;
  2249.     short    actualLineFeed = *lineFeedSize;
  2250.     
  2251.     amLowRes = ((**hImageData).vImageRes == ff(72));
  2252.     // if we are in low res mode, we double the line feed size, as all ImageWriter 
  2253.     // line feed commands are expressed at 144 dpi.
  2254.     if (amLowRes)
  2255.         *lineFeedSize <<= 1;
  2256.     
  2257.     // optimize small motions (particularlly -1 followed by +1 with no data between)
  2258.     // into groups.  This gets rid of the "paper dance" for blank colors passes.
  2259.     {    
  2260.     SpecGlobalsHdl    hGlobals = GetMessageHandlerInstanceContext();
  2261.     SpecGlobalsPtr    pGlobals = *hGlobals;
  2262.     
  2263.     if (    (pGlobals->packagingOptions == kDoSmallLineFeeds) || 
  2264.             (*lineFeedSize < -1) || 
  2265.             (*lineFeedSize > 1) )
  2266.         {
  2267.         *lineFeedSize += pGlobals->lineFeeds;
  2268.         pGlobals->lineFeeds = 0;
  2269.         // do the line feed in the default way
  2270.         anErr = Forward_GXRasterLineFeed(lineFeedSize, buffer, bufferPos, hImageData);
  2271.         }
  2272.     else
  2273.         {
  2274.         pGlobals->lineFeeds += *lineFeedSize;
  2275.         *lineFeedSize = 0;
  2276.         anErr = noErr;
  2277.         }
  2278.     }
  2279.     
  2280.     // and if in low quality mode, we divide the result to make up for the multiplication
  2281.     // that we do above
  2282.     if (amLowRes)
  2283.         *lineFeedSize >>= 1;    
  2284.             
  2285.     return(anErr);
  2286.     
  2287. } // SD_LineFeed
  2288.  
  2289. //<FF>
  2290. /* ------------------------------------------------------------------------------------    */
  2291. OSErr SD_PackageBitmap (
  2292.     gxRasterPackageBitmapRec    *pPackage,
  2293.     Ptr                         buffer,     // data goes here + bufferPos
  2294.     unsigned long                 *bufferPos,    // how much of the buffer already is full
  2295.     gxRasterImageDataHdl         hImageData)    // private image data
  2296. /*
  2297.     Packages a bitmap for the ImageWriter
  2298.     This routine is called in order to add your rotated and packaged pixel
  2299.     data to the buffer.  It is called once for each head pass.  This routine
  2300.     is pretty complex because it also does IW run length compression.  
  2301.     
  2302.     It must do the following:
  2303.         
  2304.     1)    Start filling the buffer from buffer+bufferPos.  Remember
  2305.         that this pointer may not be word aligned - so be careful
  2306.         assigning things into it.
  2307.         
  2308.     2)    If your printer does SetMargins, put a "fake" set of commands at
  2309.         the begining of the data.  Since most of the time you don't
  2310.         know the margins, you can save away the value of the bufferPos,
  2311.         and backpatch it after you have finished with the offscreen.
  2312.         SetMargins is used on printers that allow you to not send starting
  2313.         and ending whitespace.
  2314.         
  2315.     3)    Add in the rotated data for your printer.  The data to stuff starts
  2316.         at location startY in hOffscreen.  Stuff the bits from here until
  2317.         you reach startY+<your band size>, which is the size of your single
  2318.         band in this resolution mode.  Increment your number by 
  2319.         <your pass offset> + 1, which is the number of microspaces
  2320.         you will send between head passes to form this band.   Take care
  2321.         that you don't step off of the end of the offscreen in this operation,
  2322.         you may be called with startY at the end of the offscreen if the first part
  2323.         of the band is white.
  2324.         
  2325.         colorBand contains the color band which you should be stuffing, from
  2326.         1 to the number of color passes your printer needs (usually 4).
  2327.         Pack in the correct color band.  The packager will call you once
  2328.         for each color band, and correctly handle line feeds and backward
  2329.         line feeds to do the correct thing.  If your printer takes full
  2330.         RGB or CYMK data, I would define your number of colors to be
  2331.         1 and pack the full RGB or CYMK data with the one call to StuffBuffers.
  2332.         
  2333.         If you request kSendAllColors in your raster pack resource, then this
  2334.         message will always be called for all color passes, even those that
  2335.         do not have data on them.  For some printers, this is useful.  For the
  2336.         case of the ImageWriter, this option is not specified, so this message
  2337.         will only be sent for colors that actually have dirty bits within them.
  2338.         
  2339.     4)    Backpatch SetMargins from your saved value in step 2) now that you
  2340.         know the margins.
  2341.         
  2342.     5)    Increment bufferPos by the number of bytes you have
  2343.         added to the buffer.  Be sure to take into account the Set Margins
  2344.         command if you added one.
  2345.  
  2346.     
  2347. */
  2348. {
  2349. #pragma unused (isColorDirty)
  2350.  
  2351.     OSErr                    anErr;                    // would you beleive we could make mistakes?
  2352.     ScanLinePtr                pTheScanLine;            // Pointer to the start of scan line data
  2353.     unsigned short            lastDirtyCol;            // Last dirty part of the scan line
  2354.     unsigned short            firstDirty;                // First dirty pixel
  2355.     unsigned short            lastDirty;                // Last dirty pixel
  2356.     Boolean                    bandIsDirty;            // Is this band dirty?
  2357.     unsigned short            numberBytesAdded;        // Number of bytes we have added to the row
  2358.     unsigned short            repeatCount;            // Number of times we have seen this bitmap
  2359.     
  2360.     register unsigned short    whichCol;                // Index into the scan line data
  2361.     register unsigned short    x,y;                    // Index values into the offscreen
  2362.         
  2363.     register Ptr            thePtr;                    // Pointer to each Y scanline
  2364.     register unsigned char    tempColumn;                // Placeholder for the working column
  2365.     unsigned char            lastColumn;                // What was in the contents of the last column?
  2366.     
  2367.     Ptr                        basePtr;                // Pointer to current X byte
  2368.     unsigned char            outputMask;                // Mask of bit to set in rotated image
  2369.     unsigned char            inputMask;                // Mask of bit to look at in X
  2370.     unsigned char            startingInputMask;        // Mask of first bit of interest
  2371.     unsigned short            yPointerOffset;            // Increment pointer by this to get to next scanline
  2372.     
  2373.     unsigned short            endY, endX, incrY;        // To remove loop invariants.
  2374.     unsigned short            packingColor;            // number of colors packing
  2375.     unsigned long             originalBufferPos;        // where we were in the buffer before we started;
  2376.     long                    originalLineFeeds;        // how many line feeds did we have before?
  2377.     SpecGlobalsHdl            hGlobals = GetMessageHandlerInstanceContext();
  2378.     SpecGlobalsPtr            pGlobals = *hGlobals;
  2379.     
  2380. /* This macro stores one group into the pointer:
  2381.     P = Pointer to fill into
  2382.     G = Character for group
  2383.     S = Length of group run in pixels
  2384. */
  2385. #define EMITGROUP(P, G, S)                    \
  2386.         P->cEscape = ESCAPE;                \
  2387.         P->cCommand = G;                    \
  2388.         Long2Dec(S, P->cLineLength);        
  2389.  
  2390.     // save away original position in order to do a restore should the band be clean
  2391.     originalBufferPos = *bufferPos;
  2392.     originalLineFeeds = pGlobals->lineFeeds;
  2393.     if (originalLineFeeds == 0)
  2394.         {
  2395.         anErr = noErr;
  2396.         }
  2397.     else
  2398.         {
  2399.         // if we have any extra line feeds saved up, do them now!    
  2400.         pGlobals->lineFeeds = 0;
  2401.         pGlobals->packagingOptions = kDoSmallLineFeeds;
  2402.         anErr = Send_GXRasterLineFeed(&originalLineFeeds, buffer, bufferPos, hImageData);
  2403.         pGlobals = *hGlobals;
  2404.         pGlobals->packagingOptions = kNoPackagingOptions;
  2405.         }
  2406.     nrequire(anErr, SendInitialLineFeeds);
  2407.     
  2408.     /* Set color iff ImageWriterII */
  2409.     if ((**hGlobals).isImageWriterII)
  2410.         {
  2411.         pTheScanLine = (ScanLinePtr) (buffer + kSetMarginsSize + (*bufferPos));
  2412.         
  2413.         /* Set color mode for this scan line, if needed */
  2414.         pTheScanLine->cColorEscape        = ESCAPE;
  2415.         pTheScanLine->cSetColorCommand    = kSetColorCommand;
  2416.         
  2417.         packingColor = (*hImageData)->packagingInfo.colorPasses;
  2418.         if (packingColor == 4)
  2419.             switch (pPackage->colorBand)
  2420.                 {
  2421.                 case 1: // yellow
  2422.                     pTheScanLine->cColor    = '1';
  2423.                     startingInputMask = 0x10;
  2424.                     break;
  2425.                     
  2426.                 case 2: // magenta
  2427.                     pTheScanLine->cColor    = '2';
  2428.                     startingInputMask = 0x20;
  2429.                     break;
  2430.     
  2431.                 case 3: // cyan
  2432.                     pTheScanLine->cColor    = '3';
  2433.                     startingInputMask = 0x40;
  2434.                     break;
  2435.                     
  2436.                 case 4: // black
  2437.                     pTheScanLine->cColor    = '0';
  2438.                     startingInputMask = 0x80;
  2439.                     break;
  2440.                     
  2441.                 }
  2442.         else
  2443.             {
  2444.             pTheScanLine->cColor = '0';
  2445.             startingInputMask = 0x80;
  2446.             }
  2447.         }
  2448.     else    /* Backup to eliminate cColorEscape, cSetColorCommand and cColor */
  2449.         {
  2450.         pTheScanLine = (ScanLinePtr) (buffer + kSetMarginsSize + (*bufferPos) - 3);
  2451.         packingColor = (*hImageData)->packagingInfo.colorPasses;
  2452.         startingInputMask = 0x80;
  2453.         }
  2454.  
  2455.     /* Start with the first bit in the offscreen */
  2456.     inputMask = startingInputMask;
  2457.         
  2458.     /* We start out with no dirty bits */
  2459.     firstDirty = 0;
  2460.     lastDirty = 0;
  2461.     bandIsDirty = false;
  2462.     
  2463.     /* Set our array index to zero */
  2464.     whichCol = 0;
  2465.     lastDirtyCol = 0;
  2466.     numberBytesAdded = 0;
  2467.     
  2468.     /* Set up RLL variables */
  2469.     repeatCount = 0;
  2470.     lastColumn = 0;
  2471.     
  2472.     /* Get the byte pointer for the start of this color band */
  2473.     basePtr = pPackage->bitmapToPackage->image;
  2474.     
  2475.     /* Get the byte pointer for the start of the first scan line */ 
  2476.     basePtr += pPackage->startRaster * pPackage->bitmapToPackage->rowBytes;
  2477.             
  2478.     /* Save away loop invariants */
  2479.     endY     = pPackage->startRaster + (*hImageData)->packagingInfo.headHeight;        // Ending scan line
  2480.     incrY     = (*hImageData)->packagingInfo.passOffset + 1;            // Number of scanlines to increment by
  2481.     endX     = pPackage->dirtyRect.right;                                // Ending X pos
  2482.     yPointerOffset = incrY * pPackage->bitmapToPackage->rowBytes;            // amount to add to the input
  2483.                                                             // pointer to move to the next scanline
  2484.  
  2485.     /* If the ending position is too large for the bitmap we have been given,
  2486.        truncate it, so that we don't print garbage */
  2487.     if (endY > pPackage->bitmapToPackage->height)
  2488.         endY = pPackage->bitmapToPackage->height;
  2489.     
  2490.     /* For the entire width of the offscreen, move a rolling mask along in the
  2491.        X direction, rotating up 8 bits of Y data per column.  In addition, compress
  2492.        runs of columns that are > 14 length. */
  2493.     for (x = 0; x < endX; x++)
  2494.         {        
  2495.         /* The bits in this column are clear to begin with */
  2496.         tempColumn = 0;
  2497.         
  2498.         /* Which byte to look at in the input buffer */
  2499.         thePtr = basePtr;
  2500.         
  2501.         /*     Where to place the bit in the output. The ImageWriter takes the bit
  2502.             pattern upside down. */
  2503.         outputMask = 0x01;
  2504.         
  2505.         /* Scan through this band, setting each of the 8 bits == the bit in that scan line */
  2506.         for (y = pPackage->startRaster; y < endY; y += incrY)
  2507.             {
  2508.             /* If we have a bit in the input, rotate it into the output */
  2509.             if ((*thePtr) & inputMask)
  2510.                 tempColumn |= outputMask;
  2511.  
  2512.             // move onto next position in the output data                
  2513.             outputMask <<= 1;
  2514.             
  2515.             // move onto the next scan line in the input data
  2516.             thePtr += yPointerOffset;
  2517.             } // for y
  2518.             
  2519.             
  2520.         /* Save the column info */ 
  2521.         pTheScanLine->iTheData[whichCol] = tempColumn;
  2522.         
  2523.         /* Get the next bit from the current pointer */
  2524.         inputMask >>= packingColor;
  2525.         if (!inputMask)
  2526.             {
  2527.             /* If we run out of bits, get the next byte */
  2528.             basePtr++;
  2529.             
  2530.             /* And reset the bit mask to the first bit */
  2531.             inputMask = startingInputMask;
  2532.             }
  2533.             
  2534.         /* If we have some form of data */
  2535.         if (tempColumn != 0)
  2536.             {
  2537.             if (!bandIsDirty)
  2538.                 {
  2539.                 /* This is the first dirty pixels we have so far */
  2540.                 bandIsDirty = true;
  2541.                 firstDirty = x;
  2542.                 }
  2543.             
  2544.             /* This is also the last dirty pixels so far */
  2545.             lastDirty = x;
  2546.             } // SetDirty
  2547.             
  2548.         /* If we have some dirty bits */
  2549.         if (bandIsDirty)
  2550.             {
  2551.             /* Move on to the next column */
  2552.             whichCol++;
  2553.             
  2554.             /* If this is a dirty column, then it is the last one so far */
  2555.             if (tempColumn != 0)
  2556.                 lastDirtyCol = whichCol;
  2557.             
  2558.             /* If we have a duplication, up the repeat count */
  2559.             if (tempColumn == lastColumn) // if (false) // turn off repeat groups
  2560.                 {
  2561.                 repeatCount++;
  2562.                 if (repeatCount == 14)
  2563.                     {
  2564.                     /* Kick out the old group */
  2565.                     whichCol -= 14;
  2566.                         EMITGROUP(pTheScanLine, kGraphicsCommand, whichCol);
  2567.                         numberBytesAdded += whichCol + kGroupSize;
  2568.                         pTheScanLine = (ScanLinePtr)(((Ptr) pTheScanLine) +
  2569.                             whichCol + kGroupSize);
  2570.                     
  2571.                     whichCol = 1;
  2572.                     lastDirtyCol = 1;
  2573.                     pTheScanLine->iTheData[0] = tempColumn;
  2574.                     }
  2575.                 }
  2576.             else
  2577.                 {
  2578.                 /* If we were repeating, emit the repeat group */
  2579.                 if (repeatCount >= 14)
  2580.                     {
  2581.                     EMITGROUP(pTheScanLine, kRepeatGroup, repeatCount);
  2582.                     numberBytesAdded += 1 + kGroupSize;
  2583.                     pTheScanLine = (ScanLinePtr) (((Ptr) pTheScanLine) + 
  2584.                         1 + kGroupSize);
  2585.                         
  2586.                     whichCol = 1;
  2587.                     lastDirtyCol = 1;
  2588.                     pTheScanLine->iTheData[0] = tempColumn;
  2589.                     }
  2590.                 repeatCount = 0;
  2591.                 lastColumn = tempColumn;
  2592.                 }
  2593.                 
  2594.             } // BandIsDirty
  2595.             
  2596.         } // end of loop for width of bitmap
  2597.  
  2598.     /* if we have a dirty band - emit the final bit of data we have
  2599.        packaged up */
  2600.     if (bandIsDirty)
  2601.         {            
  2602.         
  2603.         /* Set the margins to be the first and last dirty pixels in the scan line -
  2604.            the ImageWriter only does left margin optimization. */
  2605.         {
  2606.             SetMarginsPtr        marginBuffer;
  2607.             SpecGlobalsHdl         hGlobals = GetMessageHandlerInstanceContext();
  2608.             
  2609.             check(hGlobals);
  2610.             
  2611.             /* Get the location for placing the set margin command */
  2612.             marginBuffer = (SetMarginsPtr) (buffer + (*bufferPos));
  2613.             
  2614.             /* Stuff in the set margin command */
  2615.             marginBuffer->cEscape  = ESCAPE;
  2616.             marginBuffer->cCommand = kSetMarginsCommand;
  2617.             
  2618.             /* convert left margin into ASCII and place it at the start of the buffer */
  2619.             Long2Dec((**hGlobals).leftMargin + firstDirty, (Ptr)(marginBuffer->cIndentDistance));
  2620.         }
  2621.         
  2622.         /* Send the last group command */
  2623.         if (repeatCount < 14)
  2624.             {
  2625.             /* Emit a normal group */
  2626.             EMITGROUP(pTheScanLine, kGraphicsCommand, lastDirtyCol);
  2627.             numberBytesAdded += lastDirtyCol + kGroupSize;
  2628.             }
  2629.         else
  2630.             {
  2631.             /* Don't stuff a final repeat group if it's blank space */
  2632.             if (tempColumn != 0)
  2633.                 {
  2634.                 /* Emit a repeat group */
  2635.                 EMITGROUP(pTheScanLine, kRepeatGroup, repeatCount);
  2636.                 numberBytesAdded += 1 + kGroupSize;
  2637.                 }
  2638.             } // end of repeatCount < 14
  2639.                     
  2640.         
  2641.         /*    Increment the count of the buffer by bytes added for groups, plus
  2642.             the header, if any, plus the set margins command */
  2643.         (*bufferPos) += numberBytesAdded + kScanLineSize + kSetMarginsSize;
  2644.  
  2645.         /* and put a <cr> at the end of the line */
  2646.         *(char*)(buffer + (*bufferPos)) = '\n';
  2647.         (*bufferPos) += 1;
  2648.         
  2649.         } // bandIsDirty
  2650.     else
  2651.         {
  2652.         // don't output data if we didn't have any!
  2653.         *bufferPos = originalBufferPos;
  2654.  
  2655.         // restore original number of line feeds
  2656.         pGlobals = *hGlobals;
  2657.         pGlobals->lineFeeds = originalLineFeeds;
  2658.         } // band is not dirty
  2659.         
  2660.     // always return your errors!
  2661. SendInitialLineFeeds:
  2662.     return(anErr);
  2663.     
  2664. } // SD_PackageBitmap
  2665.  
  2666.  
  2667. /*    ______________________________________________________________
  2668.  
  2669.     SD_DefaultDesktopPrinter -
  2670.     
  2671.     This routine is a total override of the gxDefaultDesktopPrinter
  2672.     message.
  2673.     
  2674.     WHY THIS IS IMPORTANT:
  2675.     
  2676.     It stores the name of the desktop printer GX just created
  2677.     in our global "class context" data.  This way, we can retrieve
  2678.     the name from our gxChooserMessage override, use the name to
  2679.     identify the desktop printer file, and rename it.
  2680.  
  2681.     ______________________________________________________________    */
  2682.  
  2683. OSErr SD_DefaultDesktopPrinter(Str31 dtpName)
  2684. {
  2685.     OSErr                    err;
  2686.     ChooserGlobalsHdl        hGlobals;
  2687.  
  2688.     err = Forward_GXDefaultDesktopPrinter(dtpName);
  2689.     nrequire(err, ErrorOccurred);
  2690.  
  2691. /*
  2692.     Set up our class context globals, if there's no handle already stored
  2693.     there.  Then, copy the dtp name into these globals.  This handle gets
  2694.     tossed in our gxChooserMessage override.  Why use the class
  2695.     context instead of the instance context?  Because a different
  2696.     instance of our code receives the gxDefaultDesktopPrinter message
  2697.     than the gxChooserMessage.  Setting the instance context won't get
  2698.     the data to our gxChooserMessage override.
  2699. */
  2700.     hGlobals = (ChooserGlobalsHdl) GetMessageHandlerClassContext();
  2701.     if (hGlobals == nil)
  2702.     {
  2703.         hGlobals = (ChooserGlobalsHdl) TempNewHandle(sizeof(ChooserGlobals), &err);
  2704.         nrequire(err, ErrorOccurred);
  2705.         (*hGlobals)->ownerCount = 0;
  2706.         SetMessageHandlerClassContext(hGlobals);
  2707.     }
  2708.  
  2709.     ++(*hGlobals)->ownerCount;
  2710.     BlockMove(dtpName, &(*hGlobals)->dtpName, (long) dtpName[0] +1L);
  2711.  
  2712. ErrorOccurred:
  2713.     return err;
  2714. }
  2715.  
  2716.  
  2717. /*    ______________________________________________________________
  2718.  
  2719.     SD_ChooserMessage -
  2720.     
  2721.     This routine is a total override of the gxChooserMessage
  2722.     message.
  2723.     
  2724.     WHY THIS IS IMPORTANT:
  2725.     
  2726.     This routine checks for "left button" presses, which indicate
  2727.     that the Chooser's "Create" button was pressed.  In this case,
  2728.     after forwarding the message so that the DTP is created, we
  2729.     rename the DTP.
  2730.  
  2731.     ______________________________________________________________    */
  2732.  
  2733. OSErr SD_ChooserMessage(short message, short caller, StringPtr objName,
  2734.                         StringPtr zoneName, ListHandle theList, long p2)
  2735. {
  2736.     OSErr                err;
  2737.     ChooserGlobalsHdl    hGlobals;
  2738.  
  2739. /*
  2740.     Forward the message so that GX handles the Chooser message
  2741.     appropriately.  If the user hit Create, rename the DTP as
  2742.     we like and clear our global data.
  2743. */
  2744.     err = Forward_GXChooserMessage(message, caller, objName, zoneName, theList, p2);
  2745.  
  2746.     if ((message == buttonMsg) && ((p2 & 0xFF) == 1))    // left button was hit.
  2747.     {
  2748.         if (!err) err = MyRenameDTPs();
  2749.  
  2750.         hGlobals = (ChooserGlobalsHdl) GetMessageHandlerClassContext();
  2751.  
  2752.         if (hGlobals && (--(*hGlobals)->ownerCount == 0))
  2753.         {
  2754.             DisposHandle((Handle) hGlobals);
  2755.             SetMessageHandlerClassContext(nil);
  2756.         }
  2757.     }
  2758.  
  2759.     return err;
  2760. }
  2761.  
  2762.  
  2763. /*    ______________________________________________________________
  2764.  
  2765.     MyRenameDTPs -
  2766.     
  2767.     This routine renames the desktop printer whose name is
  2768.     stored in our class context data by SD_DefaultDesktopPrinter.
  2769.     In this example, we try to rename the DTP "Dave's DTP" and
  2770.     then append a "1, 2, 3…" as necessary if that name is taken.
  2771.     You'd probably want to rename the DTP's to something a little
  2772.     more useful.
  2773.     
  2774.     WHY THIS IS IMPORTANT:
  2775.     
  2776.     This routine renames a newly created desktop printer file.
  2777.     Note that this routine assumes that desktop printer files
  2778.     are created on the desktop and that the default desktop
  2779.     printer name is stored in the System File in 'STR ' -8192.
  2780.     These assumptions are valid now, but subject to change under
  2781.     future versions of QuickDraw GX.
  2782.  
  2783.     ______________________________________________________________    */
  2784.  
  2785. OSErr MyRenameDTPs()
  2786. {
  2787.     OSErr                err = noErr;
  2788.     FSSpec                DTPFSSpec;
  2789.     short                vRefNum, loop = 0;
  2790.     Str63                numStr, newName = "\pDave's DTP";
  2791.     long                numLen, orgLen = newName[0] +1, parDirID;
  2792.     ChooserGlobalsHdl    hGlobals = (ChooserGlobalsHdl) GetMessageHandlerClassContext();
  2793.  
  2794. /*
  2795.     If our globals have been created, get the desktop folder's
  2796.     location and make an FSSpec for the desktop printer.
  2797. */
  2798.     require(hGlobals, NoGlobals);
  2799.     err = FindFolder(kOnSystemDisk, kDesktopFolderType, kCreateFolder,
  2800.                      &vRefNum, &parDirID);
  2801.  
  2802.     nrequire(err, FindFolder_Failed);
  2803.     err = FSMakeFSSpec(vRefNum, parDirID, (*hGlobals)->dtpName, &DTPFSSpec);
  2804.     nrequire(err, FSMakeFSSpec_Failed);
  2805.  
  2806.  
  2807. // Rename the DTP, appending a 1, 2, 3… as necessary.
  2808.  
  2809.     do
  2810.     {
  2811.         if (loop != 0)
  2812.         {
  2813.             NumToString(loop, numStr);
  2814.             numLen = numStr[0]+1;
  2815.             numStr[0] = ' ';
  2816.             BlockMove(numStr, &newName[orgLen], numLen);
  2817.             newName[0] = orgLen +numLen -1;
  2818.         }
  2819.  
  2820.         err = FSpRename(&DTPFSSpec, newName);
  2821.         loop++;
  2822.     }
  2823.     while (err == dupFNErr);
  2824.  
  2825.  
  2826. /*
  2827.     Remember to change the default printer string in the system
  2828.     file so that the newly named DTP will still be the default!
  2829.     Note that if the default string doesn't exist, we don't add
  2830.     one.  If a future version of GX no longer uses the 'STR '
  2831.     resource, there's no point in adding one.
  2832. */
  2833.     if (!err)
  2834.     {
  2835.         Handle    defaultString;
  2836.         short    oldResFile = CurResFile();
  2837.         
  2838.         UseResFile(0);
  2839.         defaultString = Get1Resource('STR ', -8192);
  2840.  
  2841.         if (defaultString)
  2842.         {
  2843.             RmveResource(defaultString);
  2844.             DisposHandle(defaultString);
  2845.             
  2846.             defaultString = NewHandle((long) newName[0] +1L);
  2847.             BlockMove(newName, *defaultString, (long) newName[0] +1L);
  2848.             AddResource(defaultString, 'STR ', -8192, "\p");
  2849.             WriteResource(defaultString);
  2850.             ReleaseResource(defaultString);
  2851.         }    
  2852.         
  2853.         UseResFile(oldResFile);
  2854.     }
  2855.     
  2856. FSMakeFSSpec_Failed:
  2857. FindFolder_Failed:
  2858. NoGlobals:
  2859.     return err;
  2860. }
  2861.